How does Django middleware work?
Django middleware is a framework of hooks that sits between the WSGI/ASGI server and your view layer. Every HTTP request passes through each active middleware in order before reaching the view, and the response passes back through them in reverse order. This gives you a clean place to implement cross-cutting concerns — authentication, logging, session handling, CSRF protection — without polluting view code.
Middleware is configured in `settings.MIDDLEWARE` as an ordered list of dotted-path strings. Order matters: a middleware earlier in the list wraps all subsequent ones, so `SecurityMiddleware` must come first to enforce HTTPS redirects before anything else runs.
A middleware class implements up to five hook methods. `__init__(self, get_response)` is called once at server startup and receives a callable representing the rest of the middleware chain. `__call__(self, request)` is invoked on every request — you call `self.get_response(request)` to pass control downstream and get a response back, allowing you to modify both sides. The optional `process_view(request, view_func, view_args, view_kwargs)` hook fires after URL resolution but before the view executes, which is where CSRF validation happens. `process_exception(request, exception)` fires if the view raises. `process_template_response(request, response)` fires if the response has a `render()` method.
Django 1.10 introduced the new-style "callable" middleware, replacing the older class-based hooks (`process_request`, `process_response`). The callable style is cleaner because the entire request-response cycle is visible in one `__call__` method rather than split across two methods.
Practical example: a request-timing middleware wraps `get_response` with `time.perf_counter()` calls and appends a `X-Request-Duration` header to every response. Because it lives outside the view, it captures database and template rendering time too.
For async Django (ASGI), middleware must declare `async_capable = True` and implement `async def __call__`. Mixing sync and async middleware in the stack forces Django to run thread-pool adapters, which adds overhead — keep the stack homogeneous when running async workloads.
Common built-in middleware: `SecurityMiddleware` (HTTPS, HSTS, content-type sniffing), `SessionMiddleware`, `AuthenticationMiddleware` (depends on `SessionMiddleware` being earlier), `CsrfViewMiddleware`, `MessageMiddleware`.
Explains the request/response wrapping model, describes __call__ and get_response, and mentions that order in MIDDLEWARE list matters.
Covers all five hook methods, explains old-style vs. new-style middleware, addresses async middleware, and gives a concrete example of a custom middleware with real code logic.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment