Chapter 1 · What Django is

1.2 How Django is extended

Django is extended at its extension points: places where it calls code that is not its own, named in a setting, handed to a registry or found by a convention. Most are a dotted path in a setting, which import_string turns into a class; Django makes an object of it and keeps it for a process, a request, a thread or an asynchronous context, or makes one at each use. Three matter most: the applications a project is made of, the middleware every request passes through, and the backends behind its database, cache, files and mail.

A setting holds a name, not the object. The settings module is imported when a setting is first read, and a module it imported may read the settings in turn: django.conf.global_settings, Django’s default settings, cannot import the translation module, which “depends on the settings”. A name puts the import off until the object is first wanted. What Django is shows a new project’s names.

The pattern

A dotted path is a module’s path with one more name after the last dot. import_string imports the module and returns that attribute of it (import_string; Importing by name: import_string and autodiscover_modules).

The default CACHES is one extension point whole: its alias "default" names LocMemCache, which is called with the alias’s "LOCATION" and the rest of its dictionary, both empty here. In the figure, look for when the path becomes a class, the base class nothing tests, and what keeps the instance.

Figure 1.3 The default cache, from its setting to the object that serves it. The solid arrows are the code’s steps, in order; the dashed arrow is subclassing, which nothing tests.

Three of the things the figure shows differ from one point to the next. What is done with the import: most points call a class, the middleware calls a factory, a few name a function and WSGI_APPLICATION the application itself, and some import a module with importlib.import_module instead, as the database and session engines do.

What the object must be: most points have a base class that Django’s own implementations subclass, but a setting’s loading code tests it only for the installed applications, the static file finders and the default primary key; elsewhere an object need only have what Django uses of it.

And how long it lives, which is whatever holds it: an object made at import, the request, a cached_property or a functools cache on what builds it, a Local with a value for each thread or asynchronous context, or nothing, so that each use makes a new one.

The installed applications

Each entry of INSTALLED_APPS is the path of a package or of an AppConfig subclass. AppConfig.create imports a package with importlib.import_module, taking the configuration class from its submodule called apps where it finds one, and anything else with import_string; the class must subclass AppConfig. Apps.populate makes the configurations once a process, keeps them in the app registry, imports each application’s models module, and last calls each AppConfig.ready once, the place for an application’s startup code.

Django also looks inside each installed application by name: for its template tags, commands, migrations and translations with no setting, and for its templates and static files where the settings ask (MigrationLoader.migrations_module; Settings, apps and startup).

The middleware

Each entry of MIDDLEWARE is the dotted path of a factory: BaseHandler.load_middleware imports it and calls it once with the layer inside it, and what it returns is the middleware, called for each request. No base class is asked for, MiddlewareMixin being a convenience: the factory must return something other than None and may raise MiddlewareNotUsed to be left out. A server’s handler runs the factories when it is made, once a process (Building the middleware chain).

The backends

A backend is a pluggable implementation that a setting names, and six kinds share a shape. The setting maps each alias, "default" and any others, to a dictionary whose "ENGINE" (in DATABASES) or "BACKEND" (in CACHES, STORAGES, TASKS, MAILERS and TEMPLATES) names the backend, and an object made at import, such as caches, makes the backend for an alias when code asks for it. The base classes, BaseDatabaseWrapper, BaseCache, Storage, BaseTaskBackend, BaseEmailBackend and BaseEngine, are not tested when a backend is made.

They differ in how long a backend lives. caches, task_backends and connections are each a BaseConnectionHandler, which keeps backends in a Local, one for each thread or asynchronous context; ConnectionHandler’s is never shared between threads, for the reason Django’s neighbours gives. storages and engines keep one for each alias in a dictionary all threads share. TEMPLATES is a list, and a backend’s alias is its "NAME" or else the next-to-last name of its path, "django" for DjangoTemplates; engines makes the backend the first time its alias is asked for, as the system checks and get_template do for every engine, and keeps it for the process. mailers makes a new backend at each access, because mail backends had always been made for one sending, DEP 18 says.

A database’s "ENGINE" names a package, not a class: Django imports its base module and takes the class called DatabaseWrapper from it.

The other settings

Other settings name code, each loaded by import_string unless the loader says otherwise: “by module” is importlib.import_module.

Table 1.2 “Tested”: the class is checked against its base. “No default”: not in django/conf/global_settings.py.
setting: what it names loaded by made
AUTH_PASSWORD_VALIDATORS: dictionaries, a class in each "NAME" (Authentication, sessions and messages) loaded by get_password_validators django/contrib/auth/password_validation.py made once a process
AUTHENTICATION_BACKENDS: each a BaseBackend (Authentication, sessions and messages) loaded by load_backend django/contrib/auth/__init__.py made once a use
CSRF_FAILURE_VIEW: a view (Security) loaded by by get_callable: _get_failure_view django/middleware/csrf.py made once a process
DATABASE_ROUTERS: paths of router classes, or routers; no base class (Database backends) loaded by ConnectionRouter.routers django/db/utils.py made once a process
DEFAULT_AUTO_FIELD: a subclass of AutoField, tested (Models and fields) loaded by Options._get_default_pk_class django/db/models/options.py made once a model without its own primary key
DEFAULT_EXCEPTION_REPORTER: an ExceptionReporter (Views) loaded by get_exception_reporter_class django/views/debug.py made once a use
DEFAULT_EXCEPTION_REPORTER_FILTER: a SafeExceptionReporterFilter (Views) loaded by get_default_exception_reporter_filter django/views/debug.py made once a process
FILE_UPLOAD_HANDLERS: each a FileUploadHandler (Requests and responses) loaded by HttpRequest._initialize_handlers django/http/request.py made once a request
FORM_RENDERER: a BaseRenderer (Forms) loaded by get_default_renderer django/forms/renderers.py made once a process
FORMAT_MODULE_PATH: packages of format modules by locale (Internationalization and time zones) loaded by by module: iter_format_modules django/utils/formats.py made once a language
LOGGING_CONFIG: a function, given LOGGING (Settings, apps and startup) loaded by configure_logging django/utils/log.py made once, by django.setup; called only if LOGGING is not empty
MESSAGE_STORAGE: a BaseStorage (Authentication, sessions and messages) loaded by default_storage django/contrib/messages/storage/__init__.py made once a request
MIGRATION_MODULES: an application’s migrations package (Migrations) loaded by by module: MigrationLoader.load_disk django/db/migrations/loader.py made once a loader
PASSWORD_HASHERS: each a BasePasswordHasher (Authentication, sessions and messages) loaded by get_hashers django/contrib/auth/hashers.py made once a process
ROOT_URLCONF, no default: the root URLconf (URL routing) loaded by by module: URLResolver.urlconf_module django/urls/resolvers.py made once a process
SERIALIZATION_MODULES, no default: a module for each format (Caching, files, mail, signals and tasks) loaded by by module: _load_serializers django/core/serializers/__init__.py made once a process
SESSION_ENGINE: a module with a SessionBase store (Authentication, sessions and messages) loaded by by module: SessionMiddleware.__init__ django/contrib/sessions/middleware.py made the module once a process; a store once a request
SESSION_SERIALIZER: a class like django.core.signing.JSONSerializer (Authentication, sessions and messages) loaded by SessionBase.__init__ django/contrib/sessions/backends/base.py made once a session store
SIGNING_BACKEND: a Signer (Security) loaded by get_cookie_signer django/core/signing.py made once a use
STATICFILES_FINDERS: each a BaseFinder, tested (Content types, static files and the other contrib apps) loaded by get_finder django/contrib/staticfiles/finders.py made once a process
TEMPLATES’ "OPTIONS": loaders, each a django.template.loaders.base.Loader; context processors; tag modules (Templates) loaded by tag modules by module: Engine django/template/engine.py made once an engine
TEST_RUNNER: a DiscoverRunner (The test framework) loaded by by __import__: get_runner django/test/utils.py made once a test run
WSGI_APPLICATION: the application itself (Management commands) loaded by get_internal_wsgi_application django/core/servers/basehttp.py made once, by runserver

Registries

Some extension points are not settings: an object handed to a registry, or a module Django finds by name.

registry: what it holds registered by, or found in made chapter
template tag libraries: modules with a Library registered by, or found in each application’s templatetags package (get_template_tag_modules django/template/backends/django.py) made once an engine chapter Templates
lookups and transforms: Lookup and Transform classes, tested on use registered by, or found in RegisterLookupMixin.register_class_lookup django/db/models/query_utils.py made held by the class, or the field, it is registered on; an instance for each filter chapter QuerySets
system checks: functions that return messages registered by, or found in CheckRegistry.register django/core/checks/registry.py made held for the process; called at each run of the checks chapter Management commands
the admin: its site, a class SimpleAdminConfig.default_site names; a ModelAdmin for each model registered by, or found in DefaultAdminSite._setup django/contrib/admin/sites.py; AdminSite.register, called from each application’s admin module made once a process chapter The admin
management commands: each a BaseCommand registered by, or found in each application’s management/commands directory (get_commands django/core/management/__init__.py) made the list once a process; a command once a use chapter Management commands

Signals: Django calling out

A signal runs the other way. The project’s code connects a function, a receiver, to a Signal that Django made, and Django calls the receivers when it sends the signal, as a request starts and finishes or a model is saved. The signals Django sends lists them.