Edited the middleware doc for completeness, clarity, and consistency.
This commit is contained in:
parent
ae8e97384b
commit
be9f2919e0
|
@ -134,7 +134,7 @@ class BaseHandler(object):
|
||||||
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
|
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
|
||||||
|
|
||||||
# If the response supports deferred rendering, apply template
|
# If the response supports deferred rendering, apply template
|
||||||
# response middleware and the render the response
|
# response middleware and then render the response
|
||||||
if hasattr(response, 'render') and callable(response.render):
|
if hasattr(response, 'render') and callable(response.render):
|
||||||
for middleware_method in self._template_response_middleware:
|
for middleware_method in self._template_response_middleware:
|
||||||
response = middleware_method(request, response)
|
response = middleware_method(request, response)
|
||||||
|
|
|
@ -4,25 +4,28 @@ Middleware
|
||||||
|
|
||||||
Middleware is a framework of hooks into Django's request/response processing.
|
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 input
|
It's a light, low-level "plugin" system for globally altering Django's input
|
||||||
and/or output.
|
or output.
|
||||||
|
|
||||||
Each middleware component is responsible for doing some specific function. For
|
Each middleware component is responsible for doing some specific function. For
|
||||||
example, Django includes a middleware component, ``XViewMiddleware``, that adds
|
example, Django includes a middleware component,
|
||||||
an ``"X-View"`` HTTP header to every response to a ``HEAD`` request.
|
:class:`~django.middleware.transaction.TransactionMiddleware`, that wraps the
|
||||||
|
processing of each HTTP request in a database transaction.
|
||||||
|
|
||||||
This document explains how middleware works, how you activate middleware, and
|
This document explains how middleware works, how you activate middleware, and
|
||||||
how to write your own middleware. Django ships with some built-in middleware
|
how to write your own middleware. Django ships with some built-in middleware
|
||||||
you can use right out of the box; they're documented in the :doc:`built-in
|
you can use right out of the box. They're documented in the :doc:`built-in
|
||||||
middleware reference </ref/middleware>`.
|
middleware reference </ref/middleware>`.
|
||||||
|
|
||||||
Activating middleware
|
Activating middleware
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
To activate a middleware component, add it to the :setting:`MIDDLEWARE_CLASSES`
|
To activate a middleware component, add it to the
|
||||||
list in your Django settings. In :setting:`MIDDLEWARE_CLASSES`, each middleware
|
:setting:`MIDDLEWARE_CLASSES` tuple in your Django settings.
|
||||||
component is represented by a string: the full Python path to the middleware's
|
|
||||||
class name. For example, here's the default :setting:`MIDDLEWARE_CLASSES`
|
In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by
|
||||||
created by :djadmin:`django-admin.py startproject <startproject>`::
|
a string: the full Python path to the middleware's class name. For example,
|
||||||
|
here's the default value created by :djadmin:`django-admin.py startproject
|
||||||
|
<startproject>`::
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
@ -32,12 +35,33 @@ created by :djadmin:`django-admin.py startproject <startproject>`::
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
)
|
)
|
||||||
|
|
||||||
During the request phases (:meth:`process_request` and :meth:`process_view`),
|
A Django installation doesn't require any middleware —
|
||||||
Django applies middleware in the order it's defined in
|
:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like — but it's strongly
|
||||||
:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases
|
suggested that you at least use
|
||||||
(:meth:`process_template_response`, :meth:`process_response`, and
|
:class:`~django.middleware.common.CommonMiddleware`.
|
||||||
:meth:`process_exception`), the classes are applied in reverse order, from the
|
|
||||||
bottom up.
|
The order in :setting:`MIDDLEWARE_CLASSES` matters because a middleware can
|
||||||
|
depend on other middleware. For instance,
|
||||||
|
:class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the
|
||||||
|
authenticated user in the session; therefore, it must run after
|
||||||
|
:class:`~django.contrib.sessions.middleware.SessionMiddleware`.
|
||||||
|
|
||||||
|
Hooks and application order
|
||||||
|
===========================
|
||||||
|
|
||||||
|
During the request phase, before calling the view, Django applies middleware
|
||||||
|
in the order it's defined in :setting:`MIDDLEWARE_CLASSES`, top-down. Two
|
||||||
|
hooks are available:
|
||||||
|
|
||||||
|
* :meth:`process_request`
|
||||||
|
* :meth:`process_view`
|
||||||
|
|
||||||
|
During the response phase, after calling the view, middleware are applied in
|
||||||
|
reverse order, from the bottom up. Three hooks are available:
|
||||||
|
|
||||||
|
* :meth:`process_exception` (only if the view raised an exception)
|
||||||
|
* :meth:`process_template_response` (only for template responses)
|
||||||
|
* :meth:`process_response`
|
||||||
|
|
||||||
.. image:: _images/middleware.svg
|
.. image:: _images/middleware.svg
|
||||||
:alt: middleware application order
|
:alt: middleware application order
|
||||||
|
@ -47,10 +71,7 @@ bottom up.
|
||||||
If you prefer, you can also think of it like an onion: each middleware class
|
If you prefer, you can also think of it like an onion: each middleware class
|
||||||
is a "layer" that wraps the view.
|
is a "layer" that wraps the view.
|
||||||
|
|
||||||
A Django installation doesn't require any middleware -- e.g.,
|
The behavior of each hook is described below.
|
||||||
:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like -- but it's strongly
|
|
||||||
suggested that you at least use
|
|
||||||
:class:`~django.middleware.common.CommonMiddleware`.
|
|
||||||
|
|
||||||
Writing your own middleware
|
Writing your own middleware
|
||||||
===========================
|
===========================
|
||||||
|
@ -65,16 +86,19 @@ Python class that defines one or more of the following methods:
|
||||||
|
|
||||||
.. method:: process_request(self, request)
|
.. method:: process_request(self, request)
|
||||||
|
|
||||||
``request`` is an :class:`~django.http.HttpRequest` object. This method is
|
``request`` is an :class:`~django.http.HttpRequest` object.
|
||||||
called on each request, before Django decides which view to execute.
|
|
||||||
|
|
||||||
``process_request()`` should return either ``None`` or an
|
``process_request()`` is called on each request, before Django decides which
|
||||||
:class:`~django.http.HttpResponse` object. If it returns ``None``, Django will
|
view to execute.
|
||||||
continue processing this request, executing any other middleware and, then, the
|
|
||||||
appropriate view. If it returns an :class:`~django.http.HttpResponse` object,
|
It should return either ``None`` or an :class:`~django.http.HttpResponse`
|
||||||
Django won't bother calling ANY other request, view or exception middleware, or
|
object. If it returns ``None``, Django will continue processing this request,
|
||||||
the appropriate view; it'll return that :class:`~django.http.HttpResponse`.
|
executing any other ``process_request()`` middleware, then, ``process_view()``
|
||||||
Response middleware is always called on every response.
|
middleware, and finally, the appropriate view. If it returns an
|
||||||
|
:class:`~django.http.HttpResponse` object, Django won't bother calling any
|
||||||
|
other request, view or exception middleware, or the appropriate view; it'll
|
||||||
|
apply response middleware to that :class:`~django.http.HttpResponse`, and
|
||||||
|
return the result.
|
||||||
|
|
||||||
.. _view-middleware:
|
.. _view-middleware:
|
||||||
|
|
||||||
|
@ -91,14 +115,15 @@ dictionary of keyword arguments that will be passed to the view. Neither
|
||||||
``view_args`` nor ``view_kwargs`` include the first view argument
|
``view_args`` nor ``view_kwargs`` include the first view argument
|
||||||
(``request``).
|
(``request``).
|
||||||
|
|
||||||
``process_view()`` is called just before Django calls the view. It should
|
``process_view()`` is called just before Django calls the view.
|
||||||
return either ``None`` or an :class:`~django.http.HttpResponse` object. If it
|
|
||||||
returns ``None``, Django will continue processing this request, executing any
|
It should return either ``None`` or an :class:`~django.http.HttpResponse`
|
||||||
other ``process_view()`` middleware and, then, the appropriate view. If it
|
object. If it returns ``None``, Django will continue processing this request,
|
||||||
returns an :class:`~django.http.HttpResponse` object, Django won't bother
|
executing any other ``process_view()`` middleware and, then, the appropriate
|
||||||
calling ANY other request, view or exception middleware, or the appropriate
|
view. If it returns an :class:`~django.http.HttpResponse` object, Django won't
|
||||||
view; it'll return that :class:`~django.http.HttpResponse`. Response
|
bother calling any other view or exception middleware, or the appropriate
|
||||||
middleware is always called on every response.
|
view; it'll apply response middleware to that
|
||||||
|
:class:`~django.http.HttpResponse`, and return the result.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -122,19 +147,17 @@ middleware is always called on every response.
|
||||||
|
|
||||||
.. method:: process_template_response(self, request, response)
|
.. method:: process_template_response(self, request, response)
|
||||||
|
|
||||||
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a
|
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
|
||||||
subclass of :class:`~django.template.response.SimpleTemplateResponse` (e.g.
|
the :class:`~django.template.response.TemplateResponse` object (or equivalent)
|
||||||
:class:`~django.template.response.TemplateResponse`) or any response object
|
returned by a Django view or by a middleware.
|
||||||
that implements a ``render`` method.
|
|
||||||
|
|
||||||
``process_template_response()`` must return a response object that implements a
|
``process_template_response()`` is called just after the view has finished
|
||||||
``render`` method. It could alter the given ``response`` by changing
|
executing, if the response instance has a ``render()`` method, indicating that
|
||||||
``response.template_name`` and ``response.context_data``, or it could create
|
it is a :class:`~django.template.response.TemplateResponse` or equivalent.
|
||||||
and return a brand-new
|
|
||||||
:class:`~django.template.response.SimpleTemplateResponse` or equivalent.
|
|
||||||
|
|
||||||
``process_template_response()`` will only be called if the response
|
It must return a response object that implements a ``render`` method. It could
|
||||||
instance has a ``render()`` method, indicating that it is a
|
alter the given ``response`` by changing ``response.template_name`` and
|
||||||
|
``response.context_data``, or it could create and return a brand-new
|
||||||
:class:`~django.template.response.TemplateResponse` or equivalent.
|
:class:`~django.template.response.TemplateResponse` or equivalent.
|
||||||
|
|
||||||
You don't need to explicitly render responses -- responses will be
|
You don't need to explicitly render responses -- responses will be
|
||||||
|
@ -142,7 +165,7 @@ automatically rendered once all template response middleware has been
|
||||||
called.
|
called.
|
||||||
|
|
||||||
Middleware are run in reverse order during the response phase, which
|
Middleware are run in reverse order during the response phase, which
|
||||||
includes process_template_response.
|
includes ``process_template_response()``.
|
||||||
|
|
||||||
.. _response-middleware:
|
.. _response-middleware:
|
||||||
|
|
||||||
|
@ -151,21 +174,34 @@ includes process_template_response.
|
||||||
|
|
||||||
.. method:: process_response(self, request, response)
|
.. method:: process_response(self, request, response)
|
||||||
|
|
||||||
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
|
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
|
||||||
:class:`~django.http.HttpResponse` object returned by a Django view.
|
the :class:`~django.http.HttpResponse` or
|
||||||
|
:class:`~django.http.StreamingHttpResponse` object returned by a Django view
|
||||||
|
or by a middleware.
|
||||||
|
|
||||||
``process_response()`` must return an :class:`~django.http.HttpResponse`
|
``process_response()`` is called on all responses before they're returned to
|
||||||
object. It could alter the given ``response``, or it could create and return a
|
the browser.
|
||||||
brand-new :class:`~django.http.HttpResponse`.
|
|
||||||
|
It must return an :class:`~django.http.HttpResponse` or
|
||||||
|
:class:`~django.http.StreamingHttpResponse` object. It could alter the given
|
||||||
|
``response``, or it could create and return a brand-new
|
||||||
|
:class:`~django.http.HttpResponse` or
|
||||||
|
:class:`~django.http.StreamingHttpResponse`.
|
||||||
|
|
||||||
Unlike the ``process_request()`` and ``process_view()`` methods, the
|
Unlike the ``process_request()`` and ``process_view()`` methods, the
|
||||||
``process_response()`` method is always called, even if the ``process_request()``
|
``process_response()`` method is always called, even if the
|
||||||
and ``process_view()`` methods of the same middleware class were skipped because
|
``process_request()`` and ``process_view()`` methods of the same middleware
|
||||||
an earlier middleware method returned an :class:`~django.http.HttpResponse`
|
class were skipped (because an earlier middleware method returned an
|
||||||
(this means that your ``process_response()`` method cannot rely on setup done in
|
:class:`~django.http.HttpResponse`). In particular, this means that your
|
||||||
``process_request()``, for example). In addition, during the response phase the
|
``process_response()`` method cannot rely on setup done in
|
||||||
classes are applied in reverse order, from the bottom up. This means classes
|
``process_request()``.
|
||||||
defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first.
|
|
||||||
|
Finally, remember that during the response phase, middleware are applied in
|
||||||
|
reverse order, from the bottom up. This means classes defined at the end of
|
||||||
|
:setting:`MIDDLEWARE_CLASSES` will be run first.
|
||||||
|
|
||||||
|
Dealing with streaming responses
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionchanged:: 1.5
|
.. versionchanged:: 1.5
|
||||||
``response`` may also be an :class:`~django.http.StreamingHttpResponse`
|
``response`` may also be an :class:`~django.http.StreamingHttpResponse`
|
||||||
|
@ -180,10 +216,17 @@ must test for streaming responses and adjust their behavior accordingly::
|
||||||
if response.streaming:
|
if response.streaming:
|
||||||
response.streaming_content = wrap_streaming_content(response.streaming_content)
|
response.streaming_content = wrap_streaming_content(response.streaming_content)
|
||||||
else:
|
else:
|
||||||
response.content = wrap_content(response.content)
|
response.content = alter_content(response.content)
|
||||||
|
|
||||||
``streaming_content`` should be assumed to be too large to hold in memory.
|
.. note::
|
||||||
Middleware may wrap it in a new generator, but must not consume it.
|
|
||||||
|
``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 consume
|
||||||
|
it. Wrapping is typically implemented as follows::
|
||||||
|
|
||||||
|
def wrap_streaming_content(content)
|
||||||
|
for chunk in content:
|
||||||
|
yield alter_content(chunk)
|
||||||
|
|
||||||
.. _exception-middleware:
|
.. _exception-middleware:
|
||||||
|
|
||||||
|
@ -198,8 +241,9 @@ Middleware may wrap it in a new generator, but must not consume it.
|
||||||
Django calls ``process_exception()`` when a view raises an exception.
|
Django calls ``process_exception()`` when a view raises an exception.
|
||||||
``process_exception()`` should return either ``None`` or an
|
``process_exception()`` should return either ``None`` or an
|
||||||
:class:`~django.http.HttpResponse` object. If it returns an
|
:class:`~django.http.HttpResponse` object. If it returns an
|
||||||
:class:`~django.http.HttpResponse` object, the response will be returned to
|
:class:`~django.http.HttpResponse` object, the template response and response
|
||||||
the browser. Otherwise, default exception handling kicks in.
|
middleware will be applied, and the resulting response returned to the
|
||||||
|
browser. Otherwise, default exception handling kicks in.
|
||||||
|
|
||||||
Again, middleware are run in reverse order during the response phase, which
|
Again, middleware are run in reverse order during the response phase, which
|
||||||
includes ``process_exception``. If an exception middleware returns a response,
|
includes ``process_exception``. If an exception middleware returns a response,
|
||||||
|
@ -224,9 +268,9 @@ Marking middleware as unused
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
It's sometimes useful to determine at run-time whether a piece of middleware
|
It's sometimes useful to determine at run-time whether a piece of middleware
|
||||||
should be used. In these cases, your middleware's ``__init__`` method may raise
|
should be used. In these cases, your middleware's ``__init__`` method may
|
||||||
``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that
|
raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove
|
||||||
piece of middleware from the middleware process.
|
that piece of middleware from the middleware process.
|
||||||
|
|
||||||
Guidelines
|
Guidelines
|
||||||
----------
|
----------
|
||||||
|
|
Loading…
Reference in New Issue