Part I · Foundations

Chapter 1: What Django is

Django is a web framework written in Python: the code between a web server and a web application, which turns each HTTP request the server hands it into a response, keeps the application’s data as models over a relational database, and draws its pages from templates. This chapter is the map of it: the objects that carry it, how its parts lean on one another, how it is extended, and where it stops.

All of it happens in a process that Django configures once, before the first request, and then keeps. A request is a call into that process, and a view, chosen by the request’s path, decides what its response is, reading and writing rows through models and rendering text through templates. Beside that machinery Django ships tools for the developer who builds on it: the management commands, with the system checks they run, and the test framework.

It began at World Online, the web department of a newspaper in Lawrence, Kansas, whose developers drew it out of the sites they built in Python from 2003; it was made open source in 2005, and is now run by an international team of volunteers (Where Django came from, and who makes it).

A project names its parts

What a developer writes with Django is a project: a settings module; a root URLconf, the module whose list of patterns maps a path to a view; and applications, each a Python package that keeps its models, views and templates together. Much of Django’s own work arrives the same way. The admin, authentication and sessions are applications in django.contrib, listed in the settings beside the project’s own.

The settings are where a project says what it is made of, and they say much of it with dotted paths, each naming a module, a class or another object that Django will import. This is part of the settings module that django-admin startproject writes for a new project:

# settings.py as django-admin startproject writes it; some lines are left out
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # ...
    },
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        # ...
    }
}

The applications, the middleware and the backends of the templates and of the database are each named, not built in, and each could be another: the pattern by which Django loads what a setting names, and the places it is used, is How Django is extended.

The objects that carry it

The process is prepared once, before it serves anything. A server is pointed at the project’s WSGI or ASGI module, wsgi.py or asgi.py, which startproject also writes; importing it calls get_wsgi_application or get_asgi_application, which calls django.setup and then makes the handler. The settings, settings, a LazySettings, exist as soon as django.conf is imported, but read the settings module only the first time they are needed, which in setup is at once, and then keep its values. The app registry, apps, an Apps, imports every installed application and then its models, and holds an AppConfig for each application and every model class but the abstract ones.

The handler, a WSGIHandler or an ASGIHandler, is the object the server calls, once for each request. When it is made it turns the MIDDLEWARE setting into the middleware chain, the middleware nested one inside the next, and keeps it. For each request it builds an HttpRequest from what the server passed, calls the chain with it, and hands the response that comes back to the server in the server’s terms. When the request reaches the centre of the chain, the handler itself asks the resolver, a URLResolver made from the root URLconf on first use and kept, to match the request’s path against the URL patterns, and it returns the view and the arguments the path supplied. The view is any callable that takes a request and returns a response; Django asks of it only that it return one.

What a view does in between is the application’s, and two parts of Django serve it. The model, a subclass of Model, is the class through which the application reads and writes the rows of a table, a field in most cases standing for a column; its options, kept as Model._meta (an Options), hold what Django knows about it: its fields, its table, its relations, its ordering. The admin, the model forms and the migrations derive what they need from _meta. The queryset, a QuerySet, is a lazy description of a query, built up by chained calls, which a SQLCompiler of the database’s backend turns into SQL when its results are first needed. The template engine, an Engine, finds a template by name through its loaders and compiles it into a tree of nodes, which is rendered with a context. The TEMPLATES setting names not the engine but a template backend, DjangoTemplates, which wraps it in the interface every backend shares, so that Jinja2 can stand in its place. Another way into a process is a management command: manage.py calls execute_from_command_line, which calls django.setup and then runs the command.

The parts, in one picture

The objects that carry Django belong to a few departments of its source, and the figure places them, each department leaning on those beneath it: the request side, with the view at its centre; beneath the view, the presentation side and the data side, which the view uses; beneath those, the services, which any part may call on; and on the floor, the settings, the registry, the utilities and the core exceptions, which every part imports. The applications of django.contrib and the developer’s tools are built on top of all of it.

Figure 1.1 Django’s parts as departments, each leaning on those beneath it. The large box is Django; the two dashed boxes, the server above and the database below, are outside it. The accented arrows are a request’s way from the server’s call along the request side, the view at its centre accented too; the plain arrow is the data side’s way out to the database.

The picture is a map, not a set of walls: the parts do import one another, and which part imports which, and which never does, is the subject of The parts of Django, and what each leans on. The principles they are built by are written down in the project’s design philosophies, and where the code keeps them and where it bends them is The design philosophies, in the code.

One request, in brief

The server calls the handler. The request goes in through the middleware, the first in the setting first; each may answer at once and send the request no further. At the centre the resolver matches the path and the view is called. A view that shows data builds a queryset, which sends no query yet, and renders a template, and it may be the template’s loop that first reads the rows and so sends the "SELECT". The view returns a response, which goes back out through the middleware in the reverse order and on to the server, and when the response has been sent it is closed, which sends request_finished, one of the signals by which a part of Django tells any receiver that something has happened. A request, end to end follows one request through all of this, recorded from a running Django; in that request it is the loop that sends the query.

Where Django stops

Django’s handler listens on no socket: a WSGI or an ASGI server does that and calls it, and the development server that runserver starts is the one server Django ships. The models’ rows live in a database, outside Django, reached through a driver that a backend imports. Django requires two libraries beside Python, asgiref for the bridge between synchronous and asynchronous code and sqlparse for splitting and parsing SQL, and on Windows a third, tzdata; it imports others where a feature needs them, from Pillow for images to Jinja2 for a second template engine. Packages built on Django attach where it leaves a point open: Django’s neighbours.