Middleware and Routing
Every request to the cookbook, whatever its URL, needs the same chores: load the session, work out who the user is, check forms for forgery, add security headers. Writing those in every view would be madness. Django wraps all views in middleware, layers that every request passes through before routing even begins.
The rule
In from the top, out from the bottom; routing happens in the middle.
settings.MIDDLEWARE is an ordered list. A new project has:
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",
]Picture them as layers of an onion around the view. The request goes through them top to bottom; then Django resolves the URL and calls the view; the response comes back bottom to top. Order matters: AuthenticationMiddleware sits below SessionMiddleware because it reads the user from the session.
A middleware is just a callable that receives the next layer, get_response:
# recipes/middleware.py
import time
def timing(get_response):
def middleware(request):
start = time.monotonic() # on the way in
response = get_response(request) # everything below, including the view
response["X-Elapsed"] = f"{time.monotonic() - start:.3f}"
return response # on the way out
return middlewareAdd "recipes.middleware.timing" to the list and every response carries the header.
Two consequences for routing:
- A middleware may return a response without calling
get_response. Then the layers below it, the URL resolver and the view never run; the response travels back out through the layers above. That is how a "site under maintenance" switch can work. - Because the URL is resolved after the request middleware, a middleware can steer routing. Setting
request.urlconfswaps the URL patterns for that request, for example a separate set for anapi.subdomain.
Middleware classes can also define process_view(), which runs after the URL is resolved but just before the view, and is told which view was chosen.
The shortcut
To predict anything about middleware, draw the U: down the list, across to the view, back up the list. Whatever is higher in the list sees the request first and the response last.
Down the list
timingstarts its clock, then security, sessions, common, CSRF, auth, messages, clickjacking.
Drills
Answer fast — trust the rule.
In what order do responses pass through the MIDDLEWARE list?
When does Django match the URL against urlpatterns?
A maintenance middleware near the top returns a response without calling get_response. What runs next?
Why must AuthenticationMiddleware come after SessionMiddleware?
Remember
- In from the top, out from the bottom; routing and the view sit in the middle.
- Draw the U to predict order; higher layers see the request first and the response last.
- Trap: a middleware that returns early skips routing and the view entirely.
