summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2012-12-09 22:22:36 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2012-12-09 22:30:01 +0100
commitbe9f2919e0e52faa7f7177c795d20646eff89874 (patch)
tree5a0822e6afa5ac03fb2da72fa28b768742e88c96 /docs
parentae8e97384bbacaf4094b5f98c83b8599478b3fac (diff)
downloaddjango-be9f2919e0e52faa7f7177c795d20646eff89874.tar.gz
Edited the middleware doc for completeness, clarity, and consistency.
Diffstat (limited to 'docs')
-rw-r--r--docs/topics/http/middleware.txt180
1 files changed, 112 insertions, 68 deletions
diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt
index 97d4a07784..0c6858e2cf 100644
--- a/docs/topics/http/middleware.txt
+++ b/docs/topics/http/middleware.txt
@@ -4,25 +4,28 @@ 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 input
-and/or output.
+or output.
Each middleware component is responsible for doing some specific function. For
-example, Django includes a middleware component, ``XViewMiddleware``, that adds
-an ``"X-View"`` HTTP header to every response to a ``HEAD`` request.
+example, Django includes a middleware component,
+: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
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>`.
Activating middleware
=====================
-To activate a middleware component, add it to the :setting:`MIDDLEWARE_CLASSES`
-list in your Django settings. In :setting:`MIDDLEWARE_CLASSES`, each middleware
-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`
-created by :djadmin:`django-admin.py startproject <startproject>`::
+To activate a middleware component, add it to the
+:setting:`MIDDLEWARE_CLASSES` tuple in your Django settings.
+
+In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by
+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 = (
'django.middleware.common.CommonMiddleware',
@@ -32,12 +35,33 @@ created by :djadmin:`django-admin.py startproject <startproject>`::
'django.contrib.messages.middleware.MessageMiddleware',
)
-During the request phases (:meth:`process_request` and :meth:`process_view`),
-Django applies middleware in the order it's defined in
-:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases
-(:meth:`process_template_response`, :meth:`process_response`, and
-:meth:`process_exception`), the classes are applied in reverse order, from the
-bottom up.
+A Django installation doesn't require any middleware —
+: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`.
+
+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
: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
is a "layer" that wraps the view.
-A Django installation doesn't require any middleware -- e.g.,
-: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`.
+The behavior of each hook is described below.
Writing your own middleware
===========================
@@ -65,16 +86,19 @@ Python class that defines one or more of the following methods:
.. method:: process_request(self, request)
-``request`` is an :class:`~django.http.HttpRequest` object. This method is
-called on each request, before Django decides which view to execute.
+``request`` is an :class:`~django.http.HttpRequest` object.
+
+``process_request()`` is called on each request, before Django decides which
+view to execute.
-``process_request()`` should return either ``None`` or an
-:class:`~django.http.HttpResponse` object. If it returns ``None``, Django will
-continue processing this request, executing any other middleware and, then, 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 return that :class:`~django.http.HttpResponse`.
-Response middleware is always called on every response.
+It should return either ``None`` or an :class:`~django.http.HttpResponse`
+object. If it returns ``None``, Django will continue processing this request,
+executing any other ``process_request()`` middleware, then, ``process_view()``
+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:
@@ -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
(``request``).
-``process_view()`` is called just before Django calls the view. It should
-return either ``None`` or an :class:`~django.http.HttpResponse` object. If it
-returns ``None``, Django will continue processing this request, executing any
-other ``process_view()`` middleware and, then, 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 return that :class:`~django.http.HttpResponse`. Response
-middleware is always called on every response.
+``process_view()`` is called just before Django calls the view.
+
+It should return either ``None`` or an :class:`~django.http.HttpResponse`
+object. If it returns ``None``, Django will continue processing this request,
+executing any other ``process_view()`` middleware and, then, the appropriate
+view. If it returns an :class:`~django.http.HttpResponse` object, Django won't
+bother calling any other view or exception middleware, or the appropriate
+view; it'll apply response middleware to that
+:class:`~django.http.HttpResponse`, and return the result.
.. note::
@@ -122,19 +147,17 @@ middleware is always called on every response.
.. method:: process_template_response(self, request, response)
-``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a
-subclass of :class:`~django.template.response.SimpleTemplateResponse` (e.g.
-:class:`~django.template.response.TemplateResponse`) or any response object
-that implements a ``render`` method.
+``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
+the :class:`~django.template.response.TemplateResponse` object (or equivalent)
+returned by a Django view or by a middleware.
-``process_template_response()`` must return a response object that implements a
-``render`` method. It could 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.SimpleTemplateResponse` or equivalent.
+``process_template_response()`` is called just after the view has finished
+executing, if the response instance has a ``render()`` method, indicating that
+it is a :class:`~django.template.response.TemplateResponse` or equivalent.
-``process_template_response()`` will only be called if the response
-instance has a ``render()`` method, indicating that it is a
+It must return a response object that implements a ``render`` method. It could
+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.
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.
Middleware are run in reverse order during the response phase, which
-includes process_template_response.
+includes ``process_template_response()``.
.. _response-middleware:
@@ -151,21 +174,34 @@ includes process_template_response.
.. method:: process_response(self, request, response)
-``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
-:class:`~django.http.HttpResponse` object returned by a Django view.
+``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
+the :class:`~django.http.HttpResponse` or
+:class:`~django.http.StreamingHttpResponse` object returned by a Django view
+or by a middleware.
+
+``process_response()`` is called on all responses before they're returned to
+the browser.
-``process_response()`` must return an :class:`~django.http.HttpResponse`
-object. It could alter the given ``response``, or it could create and return a
-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
-``process_response()`` method is always called, even if the ``process_request()``
-and ``process_view()`` methods of the same middleware class were skipped because
-an earlier middleware method returned an :class:`~django.http.HttpResponse`
-(this means that your ``process_response()`` method cannot rely on setup done in
-``process_request()``, for example). In addition, during the response phase the
-classes are applied in reverse order, from the bottom up. This means classes
-defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first.
+``process_response()`` method is always called, even if the
+``process_request()`` and ``process_view()`` methods of the same middleware
+class were skipped (because an earlier middleware method returned an
+:class:`~django.http.HttpResponse`). In particular, this means that your
+``process_response()`` method cannot rely on setup done in
+``process_request()``.
+
+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
``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:
response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
- response.content = wrap_content(response.content)
+ 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 consume
+ it. Wrapping is typically implemented as follows::
-``streaming_content`` should be assumed to be too large to hold in memory.
-Middleware may wrap it in a new generator, but must not consume it.
+ def wrap_streaming_content(content)
+ for chunk in content:
+ yield alter_content(chunk)
.. _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.
``process_exception()`` should return either ``None`` or an
:class:`~django.http.HttpResponse` object. If it returns an
-:class:`~django.http.HttpResponse` object, the response will be returned to
-the browser. Otherwise, default exception handling kicks in.
+:class:`~django.http.HttpResponse` object, the template response and response
+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
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
-should be used. In these cases, your middleware's ``__init__`` method may raise
-``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that
-piece of middleware from the middleware process.
+should be used. In these cases, your middleware's ``__init__`` method may
+raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove
+that piece of middleware from the middleware process.
Guidelines
----------