Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Edited the middleware doc for completeness, clarity, and consistency.

  • Loading branch information...
commit be9f2919e0e52faa7f7177c795d20646eff89874 1 parent ae8e973
Aymeric Augustin authored December 09, 2012
2  django/core/handlers/base.py
@@ -134,7 +134,7 @@ def get_response(self, request):
134 134
                     raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
135 135
 
136 136
                 # If the response supports deferred rendering, apply template
137  
-                # response middleware and the render the response
  137
+                # response middleware and then render the response
138 138
                 if hasattr(response, 'render') and callable(response.render):
139 139
                     for middleware_method in self._template_response_middleware:
140 140
                         response = middleware_method(request, response)
180  docs/topics/http/middleware.txt
@@ -4,25 +4,28 @@ Middleware
4 4
 
5 5
 Middleware is a framework of hooks into Django's request/response processing.
6 6
 It's a light, low-level "plugin" system for globally altering Django's input
7  
-and/or output.
  7
+or output.
8 8
 
9 9
 Each middleware component is responsible for doing some specific function. For
10  
-example, Django includes a middleware component, ``XViewMiddleware``, that adds
11  
-an ``"X-View"`` HTTP header to every response to a ``HEAD`` request.
  10
+example, Django includes a middleware component,
  11
+:class:`~django.middleware.transaction.TransactionMiddleware`, that wraps the
  12
+processing of each HTTP request in a database transaction.
12 13
 
13 14
 This document explains how middleware works, how you activate middleware, and
14 15
 how to write your own middleware. Django ships with some built-in middleware
15  
-you can use right out of the box; they're documented in the :doc:`built-in
  16
+you can use right out of the box. They're documented in the :doc:`built-in
16 17
 middleware reference </ref/middleware>`.
17 18
 
18 19
 Activating middleware
19 20
 =====================
20 21
 
21  
-To activate a middleware component, add it to the :setting:`MIDDLEWARE_CLASSES`
22  
-list in your Django settings. In :setting:`MIDDLEWARE_CLASSES`, each middleware
23  
-component is represented by a string: the full Python path to the middleware's
24  
-class name. For example, here's the default :setting:`MIDDLEWARE_CLASSES`
25  
-created by :djadmin:`django-admin.py startproject <startproject>`::
  22
+To activate a middleware component, add it to the
  23
+:setting:`MIDDLEWARE_CLASSES` tuple in your Django settings.
  24
+
  25
+In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by
  26
+a string: the full Python path to the middleware's class name. For example,
  27
+here's the default value created by :djadmin:`django-admin.py startproject
  28
+<startproject>`::
26 29
 
27 30
     MIDDLEWARE_CLASSES = (
28 31
         'django.middleware.common.CommonMiddleware',
@@ -32,12 +35,33 @@ created by :djadmin:`django-admin.py startproject <startproject>`::
32 35
         'django.contrib.messages.middleware.MessageMiddleware',
33 36
     )
34 37
 
35  
-During the request phases (:meth:`process_request` and :meth:`process_view`),
36  
-Django applies middleware in the order it's defined in
37  
-:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases
38  
-(:meth:`process_template_response`, :meth:`process_response`, and
39  
-:meth:`process_exception`), the classes are applied in reverse order, from the
40  
-bottom up.
  38
+A Django installation doesn't require any middleware —
  39
+:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like — but it's strongly
  40
+suggested that you at least use
  41
+:class:`~django.middleware.common.CommonMiddleware`.
  42
+
  43
+The order in :setting:`MIDDLEWARE_CLASSES` matters because a middleware can
  44
+depend on other middleware. For instance,
  45
+:class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the
  46
+authenticated user in the session; therefore, it must run after
  47
+:class:`~django.contrib.sessions.middleware.SessionMiddleware`.
  48
+
  49
+Hooks and application order
  50
+===========================
  51
+
  52
+During the request phase, before calling the view, Django applies middleware
  53
+in the order it's defined in :setting:`MIDDLEWARE_CLASSES`, top-down. Two
  54
+hooks are available:
  55
+
  56
+* :meth:`process_request`
  57
+* :meth:`process_view`
  58
+
  59
+During the response phase, after calling the view, middleware are applied in
  60
+reverse order, from the bottom up. Three hooks are available:
  61
+
  62
+* :meth:`process_exception` (only if the view raised an exception)
  63
+* :meth:`process_template_response` (only for template responses)
  64
+* :meth:`process_response`
41 65
 
42 66
 .. image:: _images/middleware.svg
43 67
    :alt: middleware application order
@@ -47,10 +71,7 @@ bottom up.
47 71
 If you prefer, you can also think of it like an onion: each middleware class
48 72
 is a "layer" that wraps the view.
49 73
 
50  
-A Django installation doesn't require any middleware -- e.g.,
51  
-:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like -- but it's strongly
52  
-suggested that you at least use
53  
-:class:`~django.middleware.common.CommonMiddleware`.
  74
+The behavior of each hook is described below.
54 75
 
55 76
 Writing your own middleware
56 77
 ===========================
@@ -65,16 +86,19 @@ Python class that defines one or more of the following methods:
65 86
 
66 87
 .. method:: process_request(self, request)
67 88
 
68  
-``request`` is an :class:`~django.http.HttpRequest` object. This method is
69  
-called on each request, before Django decides which view to execute.
  89
+``request`` is an :class:`~django.http.HttpRequest` object.
  90
+
  91
+``process_request()`` is called on each request, before Django decides which
  92
+view to execute.
70 93
 
71  
-``process_request()`` should return either ``None`` or an
72  
-:class:`~django.http.HttpResponse` object. If it returns ``None``, Django will
73  
-continue processing this request, executing any other middleware and, then, the
74  
-appropriate view. If it returns an :class:`~django.http.HttpResponse` object,
75  
-Django won't bother calling ANY other request, view or exception middleware, or
76  
-the appropriate view; it'll return that :class:`~django.http.HttpResponse`.
77  
-Response middleware is always called on every response.
  94
+It should return either ``None`` or an :class:`~django.http.HttpResponse`
  95
+object. If it returns ``None``, Django will continue processing this request,
  96
+executing any other ``process_request()`` middleware, then, ``process_view()``
  97
+middleware, and finally, the appropriate view. If it returns an
  98
+:class:`~django.http.HttpResponse` object, Django won't bother calling any
  99
+other request, view or exception middleware, or the appropriate view; it'll
  100
+apply response middleware to that :class:`~django.http.HttpResponse`, and
  101
+return the result.
78 102
 
79 103
 .. _view-middleware:
80 104
 
@@ -91,14 +115,15 @@ dictionary of keyword arguments that will be passed to the view. Neither
91 115
 ``view_args`` nor ``view_kwargs`` include the first view argument
92 116
 (``request``).
93 117
 
94  
-``process_view()`` is called just before Django calls the view. It should
95  
-return either ``None`` or an :class:`~django.http.HttpResponse` object. If it
96  
-returns ``None``, Django will continue processing this request, executing any
97  
-other ``process_view()`` middleware and, then, the appropriate view. If it
98  
-returns an :class:`~django.http.HttpResponse` object, Django won't bother
99  
-calling ANY other request, view or exception middleware, or the appropriate
100  
-view; it'll return that :class:`~django.http.HttpResponse`. Response
101  
-middleware is always called on every response.
  118
+``process_view()`` is called just before Django calls the view.
  119
+
  120
+It should return either ``None`` or an :class:`~django.http.HttpResponse`
  121
+object. If it returns ``None``, Django will continue processing this request,
  122
+executing any other ``process_view()`` middleware and, then, the appropriate
  123
+view. If it returns an :class:`~django.http.HttpResponse` object, Django won't
  124
+bother calling any other view or exception middleware, or the appropriate
  125
+view; it'll apply response middleware to that
  126
+:class:`~django.http.HttpResponse`, and return the result.
102 127
 
103 128
 .. note::
104 129
 
@@ -122,19 +147,17 @@ middleware is always called on every response.
122 147
 
123 148
 .. method:: process_template_response(self, request, response)
124 149
 
125  
-``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a
126  
-subclass of :class:`~django.template.response.SimpleTemplateResponse` (e.g.
127  
-:class:`~django.template.response.TemplateResponse`) or any response object
128  
-that implements a ``render`` method.
  150
+``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
  151
+the :class:`~django.template.response.TemplateResponse` object (or equivalent)
  152
+returned by a Django view or by a middleware.
129 153
 
130  
-``process_template_response()`` must return a response object that implements a
131  
-``render`` method. It could alter the given ``response`` by changing
132  
-``response.template_name`` and ``response.context_data``, or it could create
133  
-and return a brand-new
134  
-:class:`~django.template.response.SimpleTemplateResponse` or equivalent.
  154
+``process_template_response()`` is called just after the view has finished
  155
+executing, if the response instance has a ``render()`` method, indicating that
  156
+it is a :class:`~django.template.response.TemplateResponse` or equivalent.
135 157
 
136  
-``process_template_response()`` will only be called if the response
137  
-instance has a ``render()`` method, indicating that it is a
  158
+It must return a response object that implements a ``render`` method. It could
  159
+alter the given ``response`` by changing ``response.template_name`` and
  160
+``response.context_data``, or it could create and return a brand-new
138 161
 :class:`~django.template.response.TemplateResponse` or equivalent.
139 162
 
140 163
 You don't need to explicitly render responses -- responses will be
@@ -142,7 +165,7 @@ automatically rendered once all template response middleware has been
142 165
 called.
143 166
 
144 167
 Middleware are run in reverse order during the response phase, which
145  
-includes process_template_response.
  168
+includes ``process_template_response()``.
146 169
 
147 170
 .. _response-middleware:
148 171
 
@@ -151,21 +174,34 @@ includes process_template_response.
151 174
 
152 175
 .. method:: process_response(self, request, response)
153 176
 
154  
-``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the
155  
-:class:`~django.http.HttpResponse` object returned by a Django view.
  177
+``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
  178
+the :class:`~django.http.HttpResponse` or
  179
+:class:`~django.http.StreamingHttpResponse` object returned by a Django view
  180
+or by a middleware.
  181
+
  182
+``process_response()`` is called on all responses before they're returned to
  183
+the browser.
156 184
 
157  
-``process_response()`` must return an :class:`~django.http.HttpResponse`
158  
-object. It could alter the given ``response``, or it could create and return a
159  
-brand-new :class:`~django.http.HttpResponse`.
  185
+It must return an :class:`~django.http.HttpResponse` or
  186
+:class:`~django.http.StreamingHttpResponse` object. It could alter the given
  187
+``response``, or it could create and return a brand-new
  188
+:class:`~django.http.HttpResponse` or
  189
+:class:`~django.http.StreamingHttpResponse`.
160 190
 
161 191
 Unlike the ``process_request()`` and ``process_view()`` methods, the
162  
-``process_response()`` method is always called, even if the ``process_request()``
163  
-and ``process_view()`` methods of the same middleware class were skipped because
164  
-an earlier middleware method returned an :class:`~django.http.HttpResponse`
165  
-(this means that your ``process_response()`` method cannot rely on setup done in
166  
-``process_request()``, for example). In addition, during the response phase the
167  
-classes are applied in reverse order, from the bottom up. This means classes
168  
-defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first.
  192
+``process_response()`` method is always called, even if the
  193
+``process_request()`` and ``process_view()`` methods of the same middleware
  194
+class were skipped (because an earlier middleware method returned an
  195
+:class:`~django.http.HttpResponse`). In particular, this means that your
  196
+``process_response()`` method cannot rely on setup done in
  197
+``process_request()``.
  198
+
  199
+Finally, remember that during the response phase, middleware are applied in
  200
+reverse order, from the bottom up. This means classes defined at the end of
  201
+:setting:`MIDDLEWARE_CLASSES` will be run first.
  202
+
  203
+Dealing with streaming responses
  204
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169 205
 
170 206
 .. versionchanged:: 1.5
171 207
     ``response`` may also be an :class:`~django.http.StreamingHttpResponse`
@@ -180,10 +216,17 @@ must test for streaming responses and adjust their behavior accordingly::
180 216
     if response.streaming:
181 217
         response.streaming_content = wrap_streaming_content(response.streaming_content)
182 218
     else:
183  
-        response.content = wrap_content(response.content)
  219
+        response.content = alter_content(response.content)
  220
+
  221
+.. note::
  222
+
  223
+    ``streaming_content`` should be assumed to be too large to hold in memory.
  224
+    Response middleware may wrap it in a new generator, but must not consume
  225
+    it. Wrapping is typically implemented as follows::
184 226
 
185  
-``streaming_content`` should be assumed to be too large to hold in memory.
186  
-Middleware may wrap it in a new generator, but must not consume it.
  227
+        def wrap_streaming_content(content)
  228
+            for chunk in content:
  229
+                yield alter_content(chunk)
187 230
 
188 231
 .. _exception-middleware:
189 232
 
@@ -198,8 +241,9 @@ Middleware may wrap it in a new generator, but must not consume it.
198 241
 Django calls ``process_exception()`` when a view raises an exception.
199 242
 ``process_exception()`` should return either ``None`` or an
200 243
 :class:`~django.http.HttpResponse` object. If it returns an
201  
-:class:`~django.http.HttpResponse` object, the response will be returned to
202  
-the browser. Otherwise, default exception handling kicks in.
  244
+:class:`~django.http.HttpResponse` object, the template response and response
  245
+middleware will be applied, and the resulting response returned to the
  246
+browser. Otherwise, default exception handling kicks in.
203 247
 
204 248
 Again, middleware are run in reverse order during the response phase, which
205 249
 includes ``process_exception``. If an exception middleware returns a response,
@@ -224,9 +268,9 @@ Marking middleware as unused
224 268
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225 269
 
226 270
 It's sometimes useful to determine at run-time whether a piece of middleware
227  
-should be used. In these cases, your middleware's ``__init__`` method may raise
228  
-``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that
229  
-piece of middleware from the middleware process.
  271
+should be used. In these cases, your middleware's ``__init__`` method may
  272
+raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove
  273
+that piece of middleware from the middleware process.
230 274
 
231 275
 Guidelines
232 276
 ----------

0 notes on commit be9f291

Please sign in to comment.
Something went wrong with that request. Please try again.