Middleware
Middleware is a framework of hooks into Django’s request/response processing.It’s a light, low-level “plugin” system for globally altering Django’s inputor output.
Each middleware component is responsible for doing some specific function. Forexample, Django includes a middleware component,AuthenticationMiddleware
, thatassociates users with requests using sessions.
This document explains how middleware works, how you activate middleware, andhow to write your own middleware. Django ships with some built-in middlewareyou can use right out of the box. They’re documented in the built-inmiddleware reference.
Writing your own middleware
A middleware factory is a callable that takes a get_response
callable andreturns a middleware. A middleware is a callable that takes a request andreturns a response, just like a view.
A middleware can be written as a function that looks like this:
- def simple_middleware(get_response):
- # One-time configuration and initialization.
- def middleware(request):
- # Code to be executed for each request before
- # the view (and later middleware) are called.
- response = get_response(request)
- # Code to be executed for each request/response after
- # the view is called.
- return response
- return middleware
Or it can be written as a class whose instances are callable, like this:
- class SimpleMiddleware:
- def __init__(self, get_response):
- self.get_response = get_response
- # One-time configuration and initialization.
- def __call__(self, request):
- # Code to be executed for each request before
- # the view (and later middleware) are called.
- response = self.get_response(request)
- # Code to be executed for each request/response after
- # the view is called.
- return response
The get_response
callable provided by Django might be the actual view (ifthis is the last listed middleware) or it might be the next middleware in thechain. The current middleware doesn’t need to know or care what exactly it is,just that it represents whatever comes next.
The above is a slight simplification – the get_response
callable for thelast middleware in the chain won’t be the actual view but rather a wrappermethod from the handler which takes care of applying view middleware, calling the view with appropriate URL arguments, andapplying template-response andexception middleware.
Middleware can live anywhere on your Python path.
init(get_response)
Middleware factories must accept a get_response
argument. You can alsoinitialize some global state for the middleware. Keep in mind a couple ofcaveats:
- Django initializes your middleware with only the
getresponse
argument,so you can’t define_init
()
as requiring any other arguments. - Unlike the
call()
method which is called once per request,init()
is called only once, when the Web server starts.
Marking middleware as unused
It’s sometimes useful to determine at startup time whether a piece ofmiddleware should be used. In these cases, your middleware’s init()
method may raise MiddlewareNotUsed
. Django willthen remove that middleware from the middleware process and log a debug messageto the django.request logger when DEBUG
is True
.
Activating middleware
To activate a middleware component, add it to the MIDDLEWARE
list inyour Django settings.
In MIDDLEWARE
, each middleware component is represented by a string:the full Python path to the middleware factory’s class or function name. Forexample, here’s the default value created by django-adminstartproject
:
- 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',
- ]
A Django installation doesn’t require any middleware — MIDDLEWARE
can be empty, if you’d like — but it’s strongly suggested that you at least useCommonMiddleware
.
The order in MIDDLEWARE
matters because a middleware can depend onother middleware. For instance,AuthenticationMiddleware
stores theauthenticated user in the session; therefore, it must run afterSessionMiddleware
. SeeMiddleware ordering for some common hints about ordering of Djangomiddleware classes.
Middleware order and layering
During the request phase, before calling the view, Django applies middleware inthe order it’s defined in MIDDLEWARE
, top-down.
You can think of it like an onion: each middleware class is a “layer” thatwraps the view, which is in the core of the onion. If the request passesthrough all the layers of the onion (each one calls get_response
to passthe request in to the next layer), all the way to the view at the core, theresponse will then pass through every layer (in reverse order) on the way backout.
If one of the layers decides to short-circuit and return a response withoutever calling its get_response
, none of the layers of the onion inside thatlayer (including the view) will see the request or the response. The responsewill only return through the same layers that the request passed in through.
Other middleware hooks
Besides the basic request/response middleware pattern described earlier, youcan add three other special methods to class-based middleware:
process_view()
processview
(_request, view_func, view_args, view_kwargs)request
is anHttpRequest
object.view_func
isthe Python function that Django is about to use. (It’s the actual functionobject, not the name of the function as a string.)view_args
is a list ofpositional arguments that will be passed to the view, andview_kwargs
is adictionary of keyword arguments that will be passed to the view. Neitherview_args
norview_kwargs
include the first view argument(request
).
process_view()
is called just before Django calls the view.
It should return either None
or an HttpResponse
object. If it returns None
, Django will continue processing this request,executing any other process_view()
middleware and, then, the appropriateview. If it returns an HttpResponse
object, Django won’tbother calling the appropriate view; it’ll apply response middleware to thatHttpResponse
and return the result.
Note
Accessing request.POST
insidemiddleware before the view runs or in process_view()
will prevent anyview running after the middleware from being able to modify theupload handlers for the request,and should normally be avoided.
The CsrfViewMiddleware
class can beconsidered an exception, as it provides thecsrf_exempt()
andcsrf_protect()
decorators which allowviews to explicitly control at what point the CSRF validation should occur.
process_exception()
processexception
(_request, exception)request
is anHttpRequest
object.exception
is anException
object raised by the view function.
Django calls process_exception()
when a view raises an exception.process_exception()
should return either None
or anHttpResponse
object. If it returns anHttpResponse
object, the template response and responsemiddleware will be applied and the resulting response returned to thebrowser. Otherwise, default exception handling kicks in.
Again, middleware are run in reverse order during the response phase, whichincludes process_exception
. If an exception middleware returns a response,the process_exception
methods of the middleware classes above thatmiddleware won’t be called at all.
process_template_response()
processtemplate_response
(_request, response)request
is anHttpRequest
object.response
istheTemplateResponse
object (or equivalent)returned by a Django view or by a middleware.
process_template_response()
is called just after the view has finishedexecuting, if the response instance has a render()
method, indicating thatit is a TemplateResponse
or equivalent.
It must return a response object that implements a render
method. It couldalter the given response
by changing response.template_name
andresponse.context_data
, or it could create and return a brand-newTemplateResponse
or equivalent.
You don’t need to explicitly render responses – responses will beautomatically rendered once all template response middleware has beencalled.
Middleware are run in reverse order during the response phase, whichincludes process_template_response()
.
Dealing with streaming responses
Unlike HttpResponse
,StreamingHttpResponse
does not have a content
attribute. As a result, middleware can no longer assume that all responseswill have a content
attribute. If they need access to the content, theymust test for streaming responses and adjust their behavior accordingly:
- if response.streaming:
- response.streaming_content = wrap_streaming_content(response.streaming_content)
- else:
- response.content = alter_content(response.content)
Note
streaming_content
should be assumed to be too large to hold in memory.Response middleware may wrap it in a new generator, but must not consumeit. Wrapping is typically implemented as follows:
- def wrap_streaming_content(content):
- for chunk in content:
- yield alter_content(chunk)
Exception handling
Django automatically converts exceptions raised by the view or by middlewareinto an appropriate HTTP response with an error status code. Certainexceptions are converted to 4xx status codes, while an unknownexception is converted to a 500 status code.
This conversion takes place before and after each middleware (you can think ofit as the thin film in between each layer of the onion), so that everymiddleware can always rely on getting some kind of HTTP response back fromcalling its get_response
callable. Middleware don’t need to worry aboutwrapping their call to get_response
in a try/except
and handling anexception that might have been raised by a later middleware or the view. Evenif the very next middleware in the chain raises anHttp404
exception, for example, your middleware won’t seethat exception; instead it will get an HttpResponse
object with a status_code
of 404.
Upgrading pre-Django 1.10-style middleware
- class
django.utils.deprecation.
MiddlewareMixin
- Django provides
django.utils.deprecation.MiddlewareMixin
to ease creatingmiddleware classes that are compatible with bothMIDDLEWARE
and theoldMIDDLEWARE_CLASSES
. All middleware classes included with Djangoare compatible with both settings.
The mixin provides an init()
method that accepts an optionalget_response
argument and stores it in self.get_response
.
The call()
method:
- Calls
self.process_request(request)
(if defined). - Calls
self.get_response(request)
to get the response from latermiddleware and the view. - Calls
self.process_response(request, response)
(if defined). - Returns the response.If used with
MIDDLEWARECLASSES
, the_call
()
method willnever be used; Django callsprocess_request()
andprocess_response()
directly.
In most cases, inheriting from this mixin will be sufficient to make anold-style middleware compatible with the new system with sufficientbackwards-compatibility. The new short-circuiting semantics will be harmless oreven beneficial to the existing middleware. In a few cases, a middleware classmay need some changes to adjust to the new semantics.
These are the behavioral differences between using MIDDLEWARE
andMIDDLEWARE_CLASSES
:
- Under
MIDDLEWARE_CLASSES
, every middleware will always have itsprocess_response
method called, even if an earlier middlewareshort-circuited by returning a response from itsprocess_request
method. UnderMIDDLEWARE
, middleware behaves more like an onion:the layers that a response goes through on the way out are the same layersthat saw the request on the way in. If a middleware short-circuits, onlythat middleware and the ones before it inMIDDLEWARE
will see theresponse. - Under
MIDDLEWARE_CLASSES
,process_exception
is applied toexceptions raised from a middlewareprocess_request
method. UnderMIDDLEWARE
,process_exception
applies only to exceptionsraised from the view (or from therender
method of aTemplateResponse
). Exceptions raised froma middleware are converted to the appropriate HTTP response and then passedto the next middleware. - Under
MIDDLEWARE_CLASSES
, if aprocess_response
method raisesan exception, theprocess_response
methods of all earlier middleware areskipped and a500 Internal Server Error
HTTP response is alwaysreturned (even if the exception raised was e.g. anHttp404
). UnderMIDDLEWARE
, an exceptionraised from a middleware will immediately be converted to the appropriateHTTP response, and then the next middleware in line will see thatresponse. Middleware are never skipped due to a middleware raising anexception.