1.3 Django’s neighbours
Django’s neighbours are the software it works with and does not contain: what calls it, what it needs, and what is built on it.
The figure draws the line between Django and its neighbours, and the calls that cross it: the server’s call into the handler, which the middleware chain carries to the view, and the database backend’s call out to its driver, made for the models and querysets the view uses.
The server
A web server owns the socket: it accepts connections, reads HTTP, and calls one Python object it was given when it started. Under WSGI it calls that object with the request’s environ and a function that starts the response; under ASGI it awaits it with a scope and two awaitable callables for messages. The object is Django’s handler, and what it does with the call is The two entry points.
A server is pointed at the object a project’s wsgi.py or asgi.py makes with get_wsgi_application or get_asgi_application, each of which runs django.setup and makes a handler. The WSGI servers Gunicorn, uWSGI, mod_wsgi and Waitress are pointed at the first; the ASGI servers Daphne, Uvicorn and Hypercorn at the second. The ASGI handler serves HTTP only: any other scope, a WebSocket’s included, it refuses with ValueError.
Django’s own tree holds one server, the one runserver starts: WSGI only, built on the standard library’s wsgiref, and by its docstring not for production. It serves the object WSGI_APPLICATION names, which in a new project is the one a production WSGI server is given. If the setting is None, it serves what get_wsgi_application returns. The development server takes it apart.
What Django requires
Django’s pyproject.toml names three dependencies beside Python 3.12 or newer: asgiref 3.12.1 or newer, sqlparse 0.5.0 or newer, and tzdata on Windows only. The first two are imported at the top of the modules that use them: asgiref before django.setup runs, since the module a server or manage.py starts from imports the signals, whose dispatcher imports asgiref, and sqlparse with a database backend’s operations, when the backend is loaded.
asgiref is the bridge between synchronous and asynchronous code, and Django’s uses of it fall into three groups.
- Calling code of either kind. Where Django calls code of the other kind, or code that may be either, it fits it to the caller.
BaseHandlerfits each layer of the middleware chain to its caller: a synchronous layer called by an asynchronous one is wrapped in.adapt_method_mode sync_to_async, which runs it on a thread, and the reverse inasync_to_sync; the centre of the chain fits the view so, andSignal.sendits asynchronous receivers. Sync and async in one chain explains the handler’s part. - The asynchronous methods.
QuerySet.agetisQuerySet.getrun bysync_to_async, andModel.asaveandBaseCache.agetare made the same way. - State that belongs to a request. asgiref’s
Localfollows a request whether it runs on a thread or as a coroutine. It holds the active language, the active time zone, the current URLconf and each connection handler’s connections, though the databases’ stay in their thread.
sqlparse serves the database backends, in three ways. BaseDatabaseOperations splits a script into statements for a RunSQL operation, a migration’s step of raw SQL, given one string; on PostgreSQL it is executed whole. BaseDatabaseOperations lays out a query for the test runner’s --debug-sql. And the introspection of SQLite and of MySQL parses SQL the database gives back, such as a table’s "CREATE TABLE" statement or a check constraint’s clause, to find constraints, their columns and, on SQLite, each column’s collation.
tzdata Django never imports. Its time zones are the standard library’s zoneinfo, which reads the system’s database of time zones and, where there is none, as on Windows, the tzdata package’s.
The database drivers
A database backend’s base module imports its driver, the library that talks to the database, at its top, under the name Database. The module is imported when the connection of its alias is first asked for, so a missing driver raises ImproperlyConfigured then, naming the driver, in the backends for PostgreSQL, MySQL and Oracle.
- PostgreSQL:
psycopg, orpsycopg2where it is absent. - MySQL and MariaDB:
MySQLdb, from the mysqlclient package. - Oracle:
oracledb. - SQLite: the standard library’s
sqlite3, so a new project, whose settings name SQLite, needs no driver installed.
Each driver raises its own exceptions, under the names PEP 249 gives them. DatabaseErrorWrapper raises each error again as Django’s class of the same name, so that code above the backend catches one IntegrityError whatever the driver. The rest is Database backends.
The libraries a feature imports
Beyond its requirements, Django imports a library only where a feature needs it, and where the import stands decides when its absence shows. Inside a function, it shows when the function runs, as with the cache clients and the hashers’ libraries. At the top of a module Django imports on demand, it shows then, as Jinja2’s does when an engine of TEMPLATES uses its backend; PyYAML’s is caught when the serializers are first registered, and becomes a stand-in that raises when called. In a try at a module’s top, it can set a flag: without docutils, the admin’s documentation pages say so.
| library | used by | absence shows | import |
|---|---|---|---|
Pillow, as PIL |
used by ImageField, model and form; image sizes; image extensions |
absence shows at the call | import Image django/Image django/get_ django/get_ django/ |
| argon2-cffi | used by Argon2 |
absence shows at the call | import Argon2 django/ |
| bcrypt | used by BCrypt, BCrypt |
absence shows at the call | import BCrypt django/ |
| redis | used by RedisCache |
absence shows at the call | import Redis django/ |
| pymemcache | used by PyMemcacheCache |
absence shows at the call | import Py django/ |
| pylibmc | used by PyLibMCCache |
absence shows at the call | import Py django/ |
Jinja2, as jinja2 |
used by the Jinja2 template backend; require_jinja2 |
absence shows as the module loads; for require_jinja2, as a flag |
import jinja2 django/jinja2 django/ |
PyYAML, as yaml |
used by the YAML serializer | absence shows at the call, by a stand-in | import yaml django/ |
| docutils | used by django |
absence shows as a flag | import docutils_ django/ |
| geoip2 | used by GeoIP2 |
absence shows at the call | import geoip2 django/ |
GDAL, a C library, through ctypes.CDLL |
used by GeoDjango’s spatial references, rasters and vector data | absence shows as the module loads | import lgdal django/ |
GEOS, a C library, through ctypes.CDLL |
used by GeoDjango’s geometries | absence shows as the module loads | import load_geos django/ |
The packages built on the extension points
A package built on Django attaches where Django leaves a point open: where it imports what a project names (How Django is extended), or outside it, around the handler or in a process of its own.
| package | attaches to | home |
|---|---|---|
| Channels | attaches to around the handler, as an ASGI application that wraps it (The two entry points) | home site |
| WhiteNoise | attaches to around the WSGI application, or in MIDDLEWARE instead |
home site |
| Django Debug Toolbar | attaches to MIDDLEWARE (Building the middleware chain), and URL patterns |
home site |
| django-allauth | attaches to MIDDLEWARE, INSTALLED_APPS and AUTHENTICATION_ |
home site |
| django-cors-headers | attaches to MIDDLEWARE |
home repository |
| django-htmx | attaches to MIDDLEWARE |
home site |
| Django REST framework | attaches to views and URL patterns (Views) | home site |
| Wagtail | attaches to INSTALLED_APPS, with models (Settings, apps and startup) |
home site |
| django CMS | attaches to INSTALLED_APPS, with models |
home site |
| django-extensions | attaches to INSTALLED_APPS, for its commands (Finding the command) |
home site |
| django-storages | attaches to STORAGES |
home site |
| django-redis | attaches to CACHES |
home repository |
| django-filter | attaches to forms, which it builds (Forms) | home site |
| crispy-forms | attaches to forms, which it renders through a template tag library of its own | home site |
| pytest-django | attaches to the test runner’s place: pytest runs the tests (The test framework) | home site |
| django-environ | attaches to the settings module, which calls it (The settings object) | home site |
| Celery | attaches to a process of its own, a worker that reads the settings and uses the ORM | home site |