How does Django
start?
App loading refactor - a story
Slide 2
Slide 2 text
Start up - Django
1.0-1.6
• At some point, a model is imported
• ModelBase.__new__() triggers
django.db.models.loading.AppCache
initialization
• Reverse relations now work
• Most other bits of code inspect
settings.INSTALLED_APPS directly
Slide 3
Slide 3 text
#3591
Slide 4
Slide 4 text
#3591
• Opened 26th February 2007 by Joseph
Kocherhans
• Django 0.96 was 23rd March 2007
• “Add support for custom app label and
verbose name”
Slide 5
Slide 5 text
2007
• February 2007 - Design decision needed
• September 2007 - Assigned to Adrian
• December 2007 - Accepted by Jacob
• Various attempted patches
PyCon 2008
• “The state of Django” - Adrian Holovaty
• Serious attempt at sprints
• Goals were:
• Change (verbose) name
• Change db_prefix
• Multiple instances of app
Slide 9
Slide 9 text
PyCon 2008
• It didn’t work.
Slide 10
Slide 10 text
PyCon 2008
• Scope became very much about rewriting
how django handles applications, not just
adding a piece of admin functionality
• class InstalledApps()
• Overloading of app_label
• Clear requirement for App.path
Slide 11
Slide 11 text
2009
• Nothing
Slide 12
Slide 12 text
2010
• February 2010 - Design decision needed
• Proposed for GSOC 2010
• “Medium complexity”
Slide 13
Slide 13 text
GSOC 2010
• Arthur Koziel (mentored by Jannis)
• Goals:
• Multiple instances of apps
• A way to avoid name clashes
• Internationalisation of application names
Slide 14
Slide 14 text
GSOC 2010
• September 2010 - “Fixed on a branch”
Slide 15
Slide 15 text
2011
• Ongoing work by Arthur and Jannis
• Some unpopular implementation details
• Metaclasses for Apps
• Reloadable app cache
Slide 16
Slide 16 text
2012
• Preston Holmes brings patch up to speed
• Lots of conflicts
• Lots of failing tests
• Died out late 2012
Slide 17
Slide 17 text
2013
• Migrations needed an app cache
Slide 18
Slide 18 text
2013
Slide 19
Slide 19 text
2013
• Still assigned to Adrian…
Slide 20
Slide 20 text
December 2013
• Aymeric takes a holiday
Slide 21
Slide 21 text
December 2013
Slide 22
Slide 22 text
December 2013
• Timezones
• Python 3
• Database transactions
• Django Debug Toolbar 1.0
• “He also did an multi-day in-depth review
and extended discussion as a technical
reviewer of Two Scoops of Django 1.6” -
Danny Roy Greenfeld
Slide 23
Slide 23 text
December 2013
• Rethinking the approach
• Minimal change
• Just get some of it working
• Old patches abandoned
Slide 24
Slide 24 text
December 2013
• class Apps()
• class AppConfig()
• No models.py required
• Customisable verbose name
• Start up code
• Customisable label and filesystem path
Slide 25
Slide 25 text
December 2013
• Merged!
Slide 26
Slide 26 text
December 2013
X
Slide 27
Slide 27 text
Django 1.7
• What does it mean for you?
• Existing projects and libraries may break
• Hopefully, it’s just because you did it wrong
Slide 28
Slide 28 text
Django 1.7
• 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”
Slide 29
Slide 29 text
Django 1.7
• Module level code which requires the apps
to be loaded will break (in models.py,)
• Likely ugettext() - use ugettext_lazy()
• Code relying on import order of models.py
files may break
• Code relying on “for app in
INSTALLED_APPS” will break
Slide 30
Slide 30 text
Django 1.7
• Internationalised names in contrib apps
• No need for admin.autodiscover() in urls
Slide 31
Slide 31 text
Use cases
• Registering signals in my project specific
app
• Making my third party application have an
internationalised name in the admin
• Customising a third party application
Slide 32
Slide 32 text
Register signals
# blog.apps
!
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)
Third party apps
# ponies.apps
!
from django import apps
from … import ugettext_lazy as _
!
class PonyConfig(apps.AppConfig):
name = 'ponies'
verbose_name = _('the stables')
!
# ponies.__init__
!
default_app_config = 'ponies.apps.PonyConfig'
Slide 35
Slide 35 text
Customising third party
# myproject.apps
!
from django.db.models.signals import post_save
from ponies.apps import PonyConfig
!
class MyPonyConfig(PonyConfig):
name = 'ponies'
def ready(self):
from ponies.models import Pony
from pony_util.signals import flush_cache
post_save.connect(flush_cache,
sender=Pony)
Slide 36
Slide 36 text
Customising third party
# myproject.settings
!
INSTALLED_APPS = (
…
'myproject.apps.MyPonyConfig',
…
)
Slide 37
Slide 37 text
The future?
• AppAdmin - more advanced API for
customising appearance of apps in the
admin
• App specific settings
Slide 38
Slide 38 text
The future? (+ponies)
• Setup time customisation of models
• Add fields
• Change field lengths
• Add indexes