25

This is a pretty simple django patterns question. My manager code usually lives in models.py, but what happens when models.py is really huge? Is there any other alternative pattern to letting your manager code live in models.py for maintainability and to avoid circular imports?

A question may be asked as to why models.py is so huge, but let's just assume it's size and breadth of utility is justified.

Taylor D. Edmiston
  • 12,088
  • 6
  • 56
  • 76
eculver
  • 497
  • 1
  • 5
  • 9

4 Answers4

33

I prefer to keep my models in models.py and managers in managers.py (forms in forms.py) all within the same app. For more generic managers, I prefer to keep them in core.managers if they can be re-used for other apps. In some of our larger apps with models/modelname.py that will contains a manager and the model code which doesn't seem bad.

Jeff Triplett
  • 2,216
  • 1
  • 16
  • 8
  • 2
    How do you then cleanly deal with models.py needing to import managers.py and vice-versa? – Jeff Dec 10 '09 at 19:50
  • 33
    managers.py shouldn't need to import models -- the model in question will always be available as `self.model` on the manager. – jacobian Dec 10 '09 at 20:23
  • 7
    That's great... unless your manager's QuerySet needs to reference another model - then you can't import it, and MUST put it in models.py (e.g. if you're excluding items that exist in another model, etc.). – Jough Dempsey Feb 25 '11 at 16:59
  • 3
    from django.db.models import get_model – Izz ad-Din Ruhulessin Jun 12 '11 at 08:47
  • 1
    @Izzad-DinRuhulessin Note that as of Django 1.9 `django.db.models.get_models` / `django.db.models.loading.get_models` are deprecated in favor of: `from django.apps import apps` with `apps.get_models()`. For one specific model, use: `apps.get_model('', '')`. – Taylor D. Edmiston Jul 04 '16 at 02:43
  • @tedmiston you should create an answer, because this is the most correct solution. – Daniel van Flymen Oct 18 '16 at 22:43
  • I just wanted to add to the above that if you need to import the model in the manager.py file exclusively for type hinting, you can place the import under an `if TYPE_CHECKING:` statement. The imported name will need to be surrounded in quotes, but there won't be circular imports as it's only TRUE for specific tools e.g. mypy. More info here: https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING – Edoardo Facchinelli Aug 19 '20 at 14:57
12

Your best bet with a large set of models is to use django modules to your advantage, and simply create a folder named models. Move your old models.py into this models folder, and rename it __init__.py. This will allow you to then separate each model into more specific files inside of this model folder.

You would then only need to import each model into your __init__.py's namespace.

So, for instance, you might want to separate it into:

yourapp/
    models/
        __init__.py # This file should import anything from your other files in this directory
        basic.py # Just an example name
        morespecificmodels.py # Just an example name
        managers.py # Might want to separate your manager into this

Then your __init__.py can just be:

from basic import * # You should replace * with each models name, most likely.
from managers import YourManager # Whatever your manager is called.

This is the structure that I use when my model files get huge, however I try to separate things into more pluggable apps as often as possible - so this is rarely used by me.

Hope this helps.

C2H5OH
  • 5,452
  • 2
  • 27
  • 39
monokrome
  • 1,377
  • 14
  • 21
9

I always place mine in managers.py. If you have a circular import issue remember that a) You can reference the model class for a manager at self.model, and b) You can do imports inside of functions.

Alex Gaynor
  • 14,353
  • 9
  • 63
  • 113
  • 1
    +1 for reminding us that you can import inside of a function. In my case I had to use an external model for my manager and I added ``apps.get_model(app_label='app_name', model_name='model_name')`` inside the method – jangeador Aug 03 '16 at 15:41
4

What I did when building Django apps was to create a [modelname].py file with just the specific model code, manager code and sometimes form code and used an __init__.py file to import then all in the models directory. This helped me atleast in keeping it managable.

TomHastjarjanto
  • 5,386
  • 1
  • 29
  • 41
  • If I was going to do this, I would put all these files inside a `models` folder. It will keep the app root clean and organize the imports better. – jangeador Aug 03 '16 at 15:43