Opened 3 years ago

Closed 16 months ago

#18907 closed Bug (fixed)

Documentation regarding population of backrefs is incorrect

Reported by: simonpercivall 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 Changed 3 years ago by ke1g

  • Cc ke1g added
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

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 Changed 3 years ago by simonpercivall

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 Changed 3 years ago by simonpercivall

  • Cc percivall@… added

comment:4 Changed 2 years ago by aaugustin

  • Type changed from Uncategorized to Bug

comment:5 Changed 16 months ago by timo

@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 Changed 16 months ago by aaugustin

  • Owner changed from nobody to aaugustin
  • Status changed from new to assigned

comment:7 Changed 16 months ago by aaugustin

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 Changed 16 months ago by aaugustin

  • Owner aaugustin deleted
  • Status changed from assigned to new

comment:9 Changed 16 months ago by Tim Graham <timograham@…>

  • Owner set to Tim Graham <timograham@…>
  • Resolution set to fixed
  • Status changed from new to closed

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