How does Django start?

The old days

(up to 1.6)

  • at some point a model is imported
  • metaclass: ModelBase.__new__() triggers django.db.models.loading.AppCache init
  • reverse relations now work
  • Most other bits of code inspect settings.INSTALLED_APPS directly

Problem is “at some point” - sometimes deploys can fail unpredictably

The long and winding road

#3591 bug

  • opened Feb 2007 (django 0.96 released March 2007)
  • “Add support for custom app label and verbose name”
  • Feb 2007 - design decision needed
  • Sept 2007 - assigned to Adrian Holovaty
  • Dec 2007 - accepted by Jacob
  • various attempted patches
  • PyCon 2008 - “The state of Django” - Adrian Holovaty - sprints - goals were similar - scope became about rewriting how django handles applications - class InstalledApps()
  • app_label is used in lots of places - which ones should change?
  • clear requirement for App.path
  • 2009 - basically nothing happened
  • Feb 2010 - revert to Design decision needed
  • Google SoC 2010 - “medium complexity” - multiple instances of apps, avoid names clashes, i18n of app names
  • Sept 2010 - “Fixed on a branch”
  • 2011 - ongoing work - unpopular details (Metaclasses for Apps, reloadable app cache)
  • 2012 - patch brought up to speed, conflicts, broken tests, effort died
  • 2013 - migrations needed an app cache
  • Dec 2013 - Aymeric takes a holiday - timezones, python 3, db txn, debug toolbar, 2 scoops review
  • and rethink the approach, minimal change

Now

  • class Apps()
  • class AppConfig()
  • no models.py required
  • customisable verbose name
  • reliable place for start up code (not just “at the bottom of models.py”)
  • customise label ...
  • merged! -> Django 1.7

What does it mean for you?

  • may break existing projects and libraries
  • hopefully it’s because you did it wrong ...
  • now have much stricter startup sequence
  • django.setup() configures settings, imports all applications
  • trying to use the app registry before it’s loaded will error “Apps not loaded”

The following will break

  • modules level code which requires the apps to be loaded will break - eg ugettext() - use ugettext_lazy() - ugettext() requires apps to be loaded
  • code relying on import order of models.py files may break
  • code relying on for app in INSTALLED_APPS

Good stuff

  • i18n names in contrib apps
  • no need for admin.autodiscover() in urls (as we have a consistent place for start up)

Use cases

  • registering signals in my project specific app
  • making my 3rd party app have an i18n name in admin
  • customise a 3rd party app
from django import apps
from django.db.models.signals import post_save

class BlogApp(apps.AppConfig):
    name = 'blog'

    def ready(self):
        from .models import Post
        from .signals import flush_cache
        post_save.connect(flush_cache, sender=Post)

# ...

INSTALLED_APPS = (
    # ...
    'blog.app.BlogApp',
    # ...
)

3rd party app with i18n verbose name

from django import apps

class PonyConfig(apps.AppConfig):
    name = 'ponies'
    verbose_name = _('mor ponies')

# ...

INSTALLED_APPS = (
    # ...
    'ponies.apps.PonyConfig',
    # ...
)

customise a 3rd party app

class MyPonyConfig(PonyConfig):

    def ready(self):
        # stuff


INSTALLED_APPS = (
    # ...
    'myproject.apps.MyPonyConfig',
    # ...
)

Note this makes it a little tricky to work out whether a model has been loaded.

Future

  • AppAdmin - more advanced API for custom appearance of apps in admin
  • App specific settings
  • set up time customise of models - add fields, change field lengths, add indexes

Table Of Contents

Previous topic

APIs are Awesome

Next topic

Cheating at Rock, Paper, Scissors

This Page