The request/response lifecycle, ordering, and short-circuiting
coreintermediateEvery middleware wraps the ENTIRE rest of the chain — its code before calling get_response(request) runs on the way IN (request processing), and its code after runs on the way OUT (response processing), for every single request, in the order MIDDLEWARE lists them going in and the REVERSE order coming back out. This is why MIDDLEWARE's order matters: SessionMiddleware must run before AuthenticationMiddleware (auth needs the session already loaded), and a middleware near the top of the list is also the last to see the response on the way out. Short-circuiting means a middleware can return an HttpResponse directly instead of calling get_response() — the request never reaches any middleware or view further down the chain, and the response starts unwinding back out immediately from that point.
Think of it as
The mental model Django's own docs use is "an onion" — request comes in through every layer from the outside in, hits the view at the very center, then the response passes back out through the same layers in reverse. This single-pass, wrap-everything shape is WHY ordering is not cosmetic: a middleware can only see what happened in layers CLOSER to the center (later in MIDDLEWARE) on the way in, because those haven't run yet when an earlier middleware's pre-get_response() code executes — and conversely, a middleware can only modify a response after every layer closer to the center has already added its own contribution, because response processing happens in reverse order, outermost last. Short-circuiting exists as a documented escape hatch specifically for "this request should never even reach the view" cases (an unauthenticated request to an admin-only path, a maintenance-mode check, a rate limit) — returning a response directly bypasses every remaining middleware AND the view entirely, which is a deliberate, sanctioned way to fail fast rather than something to work around.
What we're doing: A middleware that short-circuits with a 503 during a maintenance window, so no request reaches the view or any later middleware.
- 6
- Returning directly here means get_response() is never called — the view, and any middleware listed after this one, never run for this request.
- 7
- Placing this middleware EARLY in MIDDLEWARE matters — if it ran late, every earlier middleware (session, auth) would still do its work for a request that's about to be rejected anyway, wasted effort.
Why this works: Short-circuiting is the correct tool here specifically because "reject before doing any real work" is the goal — placing this check as early as reasonably possible in MIDDLEWARE, and returning directly rather than calling get_response(), avoids running authentication, session loading, or the view for a request that's going to be rejected regardless.
Placing a middleware that depends on request.session or request.user before SessionMiddleware/AuthenticationMiddleware in MIDDLEWARE
Wrong
Better
What you see: AttributeError, or request.user silently missing/incorrect inside the custom middleware's request-processing code — request.user does not exist yet at that point in the chain, because AuthenticationMiddleware (which sets it) has not run yet for a middleware positioned before it.
Why: A middleware's request-processing code only sees what layers ABOVE it in MIDDLEWARE have already done — since request.user is specifically set by AuthenticationMiddleware's own request-processing step, any middleware placed before it in the list runs before that assignment happens at all, not just before some unrelated step.
- SecurityMiddleware — first in, last out
- SessionMiddleware — must precede AuthenticationMiddleware
- AuthenticationMiddleware — sets request.user
- view — the center — last in, first out
Request vs response processing, by position in MIDDLEWARE
Together
Remember: Middleware wraps the whole chain in one onion-layered pass — MIDDLEWARE's order is the request-processing order going in, and the REVERSE order for response processing coming out. SessionMiddleware must precede AuthenticationMiddleware. Short-circuiting (returning a response instead of calling get_response()) is a sanctioned way to reject a request before it reaches the view or any later middleware.
See also: custom and async middleware · the built in middleware stack · login logout and authentication backends

