#21676 closed New feature (fixed)

Provide a way to run code when Django starts

Reported by: aaugustin Owned by: nobody
Component: Core (Other) Version: master
Severity: Normal Keywords: app-loading
Cc: django@…, mmitar@… Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by aaugustin)

This ticket is a subset of #3591 which can be dealt with independently. The following text summarizes discussions I've had with other core devs, mostly jezdez and ptone.

Nowadays Django has two common entry points:

1) wsgi.py, which calls django.core.wsgi.get_wsgi_application(). This triggers a few imports in Django, but not many, and it doesn’t import the project. As a consequence, settings are configured and the app registry is populated while serving the first request. get_wsgi_application() was introduced with the idea that it would be used to populate the app registry in the future.

2) manage.py, which calls django.core.management.execute_from_command_line(). Unless requires_model_validation has been set to False, this will quickly import and validate models, thus populating the app cache.

In addition, there’s an interesting entry point, or rather lack thereof:

3) DJANGO_SETTING_MODULE=myproject.settings python. It’s part of Django’s purity and we certainly want to preserve this ability.

There’s no way we can run an implement an initialization sequence in this third use case, so I’m leaving it aside. For comparison, with Rails, you can’t just start irb, you have to use script/console. The initialization process is daunting: http://guides.rubyonrails.org/initialization.html

So the most realistic option is to trigger startup code from get_wsgi_application() and execute_from_command_line(). The startup code would:

  • call apps.populate_apps() — rather than apps.populate_models()
  • for each application, call a conventional method on its configuration object, for instance AppConfig.startup()

It could be useful to provide a way to run code once models are loaded, probably with a second conventional method. (I'd like to avoid signals entirely.)

The documentation recommends defining the app config class in an app submodule. That avoids import issues that may happen when putting initialization code in the app's __init__.py. In the worst case, imports can be moved inside the startup() method.

This technique doesn't required changing manage.py and wsgi.py, which is important.

Change History (11)

comment:1 Changed 22 months ago by aaugustin

  • Summary changed from Provide a way to run code when a Django application starts to Provide a way to run code when Django starts

comment:2 Changed 22 months ago by aaugustin

  • Description modified (diff)

comment:4 Changed 22 months ago by aaugustin

In terms of API, jezdez and I just discussed the following:

  • AppConfig.apps_ready() runs after apps are loaded; by default it's a noop.
  • AppConfig.models_ready() runs after models are loaded; by default it calls AppConfig.ready() which is a noop.

Simple API: implement AppConfig.ready() (or .startup(), .configure()... The name must mean "just put your code there")

Advanced API: override .apps_ready() and .models_ready() (and don't forget to call super(), to ensure .ready() gets called eventually)

comment:5 Changed 22 months ago by streeter

  • Cc django@… added

comment:6 Changed 22 months ago by mitar

  • Cc mmitar@… added

comment:7 Changed 22 months ago by aaugustin

  • Triage Stage changed from Unreviewed to Accepted

comment:8 Changed 21 months ago by aaugustin

  • Has patch set
  • Patch needs improvement set

comment:9 Changed 21 months ago by aaugustin

  • Patch needs improvement unset
  • Triage Stage changed from Accepted to Ready for checkin

Pull request is ready. Waiting for feedback on the mailing list.

comment:10 Changed 21 months ago by Aymeric Augustin <aymeric.augustin@…>

In 0d2c8ff2be733c7cc83a023bbafe0258faa5603c:

Populated the app registry earlier at startup.

Refs #1796, #21676.

comment:11 Changed 21 months ago by aaugustin

  • Resolution set to fixed
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.
Back to Top