Opened 12 years ago

Closed 11 years ago

#18907 closed Bug (fixed)

Documentation regarding population of backrefs is incorrect

Reported by: Simon Percivall Owned by: Tim Graham <timograham@…>
Component: Documentation Version: 1.4
Severity: Normal Keywords:
Cc: ke1g, percivall@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

It is stated at https://docs.djangoproject.com/en/1.4/topics/db/queries/#how-are-the-backward-relationships-possible in the third paragraph that "the first time any model is loaded" Django iterates INSTALLED_APPS and populates backrefs. Either this is plain wrong, or the text needs clarification.

  1. I create a minimal two-app project where app2.Model2 has a reference to app1.Model1 and both app1 and app2 are in INSTALLED_APPS
  2. I create a Model1: Model1.objects.create()
  3. I write and run a script:
    from app1.models import Model1
    
    m = Model1.objects.get().model2s.all()
    
  4. and get
    Traceback (most recent call last):
      File "f.py", line 8, in <module>
        Model1.objects.get().model2s.all()
    AttributeError: 'Model1' object has no attribute 'model2s'
    

If I add import app2.models, it'll work.

Change History (9)

comment:1 by ke1g, 12 years ago

Cc: ke1g added
Triage Stage: UnreviewedAccepted

I know, from time spent with pdb searching for import order problems, that the documentation is wrong.

While there can be things in a models.py that trigger all installed apps to load, such as the use of non-lazy internationalization, many models.py files don't trigger general loading. In production the usual place that the installed apps are all loaded is in admin.autodiscover() called from the ROOT_URL_CONF, which gets imported at the first request. Under runserver, it happens sooner, during the model "validation" that runserver does explicitly. shell and some of the other management commands are not going to do it.

This might almost be a white lie, if the tutorial didn't encourage the novice to play with models in the shell.

Perhaps change "The first time any model is loaded," to "Under normal operation", and append a comment, maybe in parentheses, that "There may be times, such as when using the manage.py shell, when you must import models from more than the app of interest in order to have the reverse relationships connected."

comment:2 by Simon Percivall, 12 years ago

When running Django in a larger project, with something like mod_wsgi or gunicorn instead of runserver, and with Celery or other jobs doing background processing, models are also not auto-loaded, unless, as you say, they're loaded as a side-effect of other operations.

Changing the text to say "under normal operation", therefore, is deeply misleading.

I hesitated whether to submit this as a documentation issue or as a core bug. It might be argued that population of backrefs is a guarantee that Django actually should make. From my perspective, that would probably be the preferred solution.

comment:3 by Simon Percivall, 12 years ago

Cc: percivall@… added

comment:4 by Aymeric Augustin, 12 years ago

Type: UncategorizedBug

comment:5 by Tim Graham, 11 years ago

@augustin, has this behavior been rectified with the app loading changes in 1.7? If not, I wonder if you could briefly describe the current behavior so I could write up a patch (assuming you don't want to do so yourself).

comment:6 by Aymeric Augustin, 11 years ago

Owner: changed from nobody to Aymeric Augustin
Status: newassigned

comment:7 by Aymeric Augustin, 11 years ago

Tim, here's a proposal to replace the third paragraph of "How are the backward relationships possible?".

If you can improve the wording and commit it, that's perfect. Thank you!

The answer lies in the app registry. When Django starts, it imports each
application listed in :setting:`INSTALLED_APPS`, and then the ``models``
module inside each application. Whenever a new model class is created, Django
adds backward-relationships to related models. If the related models haven't
been imported yet, Django keeps tracks of the relationships and adds them
when the related models eventually are imported.

For this reason, it's particularly important that all the models you're using
be defined in applications listed in :setting:`INSTALLED_APPS`. Otherwise,
backwards relations may not work properly.

comment:8 by Aymeric Augustin, 11 years ago

Owner: Aymeric Augustin removed
Status: assignednew

comment:9 by Tim Graham <timograham@…>, 11 years ago

Owner: set to Tim Graham <timograham@…>
Resolution: fixed
Status: newclosed

In 5c7ac7494ab5f1cdc364f829f61ffef85ad7344b:

Fixed #18907 -- Correct docs regard population of model backrefs.

Thanks simonpercivall for the report and Aymeric for the patch.

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