Opened 7 years ago

Closed 6 years ago

Last modified 6 years ago

#25127 closed Cleanup/optimization (fixed)

document how to define models in multiple modules

Reported by: Kevin Turner Owned by: Evan Palmer
Component: Documentation Version: 1.8
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Though recent versions of Django have taken steps to support the ability have a number of models organized in a models/ package instead of a single models.py file, the Models documentation topic does not give guidance on how to do this.

Searching the web for answers turns up a lot of 2009-era results, which I believe are misleading when applied to current versions of Django.

There is a cookbook entry which looks at least halfway current.

Statements I've seen (which I think are now questionable) are:

  • If your models are not in models.py, you have to explicitly set db_table on each model.
  • ...you have to explicitly set app_label on each model
  • in models.py or models/__init__.py you have to import * from each module where you define models

There's this statement in the Django 1.7 release notes:

Application labels are assigned correctly to models even when they’re defined outside of models.py. You don’t have to set app_label explicitly any more.

which makes me think all of those things may be obsolete. Are there any constraints on where you define models now? If they're not in models.py, what do you need to do to ensure they're loaded?

Documentation on the app initilaization process still says the app's models module or package is loaded, so maybe that "you must import * in your models.py or models/__init__.py" thing is still true?

Change History (11)

comment:1 Changed 7 years ago by Tim Graham

Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Yes, I believe that last statement is correct. For example, in Django's own test suite: https://github.com/django/django/blob/bbbb7ce115ac619255100cee6dccd32ed4346d98/tests/auth_tests/models/__init__.py

comment:2 Changed 7 years ago by Aymeric Augustin

Indeed, Django 1.7's app-loading process is good at figuring out which app a given model belongs to, as long as you organize your code in a sensible way. To be safe, you should ensure that importing path.to.app.models has the side-effect of importing all models belonging to that app.

Not doing so will generally work in practice, but in theory it could lead to inconsistencies in the app-cache registry. For instance, you may be unable to query relations involving these models until they get imported, perhaps by a later HTTP request. This could manifest as random errors in production for a short time after restarting the server. You don't want to face such issues.

Technically, you don't need to import the model classes themselves into path.to.app.models. You just need to import the modules that defines them so that the model classes get created in the memory of your Python process, at which point they register themselves with the app registry.

However, it's a good idea to ensure that from path.to.app.models import WhateverModel works for any model, because that's one of the most common import patterns in Django projects. For this reason, I think we should encourage always importing all models into the models package when they're defined in submodules.

comment:3 Changed 7 years ago by Kevin Turner

Great, I think that's everything we need to know to document this.

That last point (about "always import all models into the models package") sounds like a stylistic one I'm not yet sure I agree with, but given that the modules do need to get imported in order for the classes to be registered, having the documentation suggest a canonical place to do that importing sounds like a good idea.

I guess the thing I want to get clear on is, if from path.to.app.models import WhateverModel doesn't work, is that a choice that you can make within your own project's organizational style, or is it something that will actually break interactions with django core or common third-party apps? I'm noticing there's an AppConfig.models_module. I'm not sure what users of that actually do with it, but it sounds like a thing that would break if you didn't follow that import convention.

comment:4 Changed 6 years ago by Evan Palmer

Owner: changed from nobody to Evan Palmer
Status: newassigned

comment:5 Changed 6 years ago by Tim Graham

Has patch: set
Patch needs improvement: set

PR with comments for improvement.

comment:6 Changed 6 years ago by Kevin Turner

You can then import classes directly from the models module as you normally would.

Yes, if you import them to models/__init__.py, you can import them elsewhere as .models.Robot, but .models.robot.Robot also works if you want to take advantage of that structure you created when you split things out into multiple models files.

(which for robot.Robot sounds redundant but maybe from .models.synthetics import Robot, Android would be useful.)

This is the part I feel most unsure about what to include in the documentation, because one hand I think the "There Should Be One Obvious Way To Do" it principle applies here, so it seems disadvantageous to go in to a lot of "you could import it this way or this way or..."

On the other hand, I can also imagine myself coming to this and thinking, "wait, if I have to import things as if they were in myapp.models anyway, then doesn't that sort of defeat the purpose of splitting them up?"

comment:7 Changed 6 years ago by Tim Graham

You must import the models in models/__init__.py for Django to work properly. As with normal Python, you can use either import path in your own code.

comment:8 Changed 6 years ago by Tim Graham

Patch needs improvement: unset

comment:9 Changed 6 years ago by Tim Graham <timograham@…>

Resolution: fixed
Status: assignedclosed

In 84d8d1d7:

Fixed #25127 -- Documented how to organize models in a package.

comment:10 Changed 6 years ago by Tim Graham <timograham@…>

In aa1bdc07:

[1.9.x] Fixed #25127 -- Documented how to organize models in a package.

Backport of 84d8d1d7151a4ee70ae35037d37f76a40d18da64 from master

comment:11 Changed 6 years ago by Tim Graham <timograham@…>

In 101f999:

[1.10.x] Fixed #25127 -- Documented how to organize models in a package.

Backport of 84d8d1d7151a4ee70ae35037d37f76a40d18da64 from master

Note: See TracTickets for help on using tickets.
Back to Top