Slide 1

Slide 1 text

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

Slide 6

Slide 6 text

2007 INSTALLED_APPS = ( 'django.contrib.auth', app('mypkg.auth', 'myauth', 'My cool auth app'), )

Slide 7

Slide 7 text

2007 INSTALLED_APPS = ( 'django.contrib.auth', app('mypkg.auth', { 'app_label': 'myauth', 'verbose_name': 'My cool auth app' }), )

Slide 8

Slide 8 text

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)

Slide 33

Slide 33 text

Register signals # myproject.settings ! INSTALLED_APPS = ( … 'blog.apps.BlogConfig', … )

Slide 34

Slide 34 text

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

Slide 39

Slide 39 text

Questions? @mjtamlyn github.com/mjtamlyn