mirror of
https://github.com/django/django.git
synced 2024-11-18 07:26:04 +00:00
756c390fb5
Thanks gthb Trac user for the report, kolypto StackOverflow user for the initial list and Tim Graham for the review.
289 lines
11 KiB
Plaintext
289 lines
11 KiB
Plaintext
==========
|
|
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
|
|
or output.
|
|
|
|
Each middleware component is responsible for doing some specific function. For
|
|
example, Django includes a middleware component,
|
|
:class:`~django.contrib.auth.middleware.AuthenticationMiddleware`, that
|
|
associates users with requests using sessions.
|
|
|
|
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
|
|
middleware reference </ref/middleware>`.
|
|
|
|
Activating middleware
|
|
=====================
|
|
|
|
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.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 —
|
|
: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`. See
|
|
:ref:`middleware-ordering` for some common hints about ordering of Django
|
|
middleware classes.
|
|
|
|
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.*
|
|
:alt: middleware application order
|
|
:width: 481
|
|
:height: 409
|
|
|
|
If you prefer, you can also think of it like an onion: each middleware class
|
|
is a "layer" that wraps the view.
|
|
|
|
The behavior of each hook is described below.
|
|
|
|
Writing your own middleware
|
|
===========================
|
|
|
|
Writing your own middleware is easy. Each middleware component is a single
|
|
Python class that defines one or more of the following methods:
|
|
|
|
.. _request-middleware:
|
|
|
|
``process_request``
|
|
-------------------
|
|
|
|
.. method:: process_request(request)
|
|
|
|
``request`` is an :class:`~django.http.HttpRequest` object.
|
|
|
|
``process_request()`` is called on each request, before Django decides which
|
|
view to execute.
|
|
|
|
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:
|
|
|
|
``process_view``
|
|
----------------
|
|
|
|
.. method:: process_view(request, view_func, view_args, view_kwargs)
|
|
|
|
``request`` is an :class:`~django.http.HttpRequest` object. ``view_func`` is
|
|
the Python function that Django is about to use. (It's the actual function
|
|
object, not the name of the function as a string.) ``view_args`` is a list of
|
|
positional arguments that will be passed to the view, and ``view_kwargs`` is a
|
|
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 view or exception middleware, or the appropriate
|
|
view; it'll apply response middleware to that
|
|
:class:`~django.http.HttpResponse`, and return the result.
|
|
|
|
.. note::
|
|
|
|
Accessing :attr:`request.POST <django.http.HttpRequest.POST>` or
|
|
:attr:`request.REQUEST <django.http.HttpRequest.REQUEST>` inside middleware
|
|
from ``process_request`` or ``process_view`` will prevent any view running
|
|
after the middleware from being able to :ref:`modify the upload handlers
|
|
for the request <modifying_upload_handlers_on_the_fly>`, and should
|
|
normally be avoided.
|
|
|
|
The :class:`~django.middleware.csrf.CsrfViewMiddleware` class can be
|
|
considered an exception, as it provides the
|
|
:func:`~django.views.decorators.csrf.csrf_exempt` and
|
|
:func:`~django.views.decorators.csrf.csrf_protect` decorators which allow
|
|
views to explicitly control at what point the CSRF validation should occur.
|
|
|
|
.. _template-response-middleware:
|
|
|
|
``process_template_response``
|
|
-----------------------------
|
|
|
|
.. method:: process_template_response(request, response)
|
|
|
|
``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()`` 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.
|
|
|
|
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
|
|
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()``.
|
|
|
|
.. _response-middleware:
|
|
|
|
``process_response``
|
|
--------------------
|
|
|
|
.. method:: process_response(request, response)
|
|
|
|
``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.
|
|
|
|
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`). 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
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Unlike :class:`~django.http.HttpResponse`,
|
|
:class:`~django.http.StreamingHttpResponse` does not have a ``content``
|
|
attribute. As a result, middleware can no longer assume that all responses
|
|
will have a ``content`` attribute. If they need access to the content, they
|
|
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 = 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::
|
|
|
|
def wrap_streaming_content(content)
|
|
for chunk in content:
|
|
yield alter_content(chunk)
|
|
|
|
.. _exception-middleware:
|
|
|
|
``process_exception``
|
|
---------------------
|
|
|
|
.. method:: process_exception(request, exception)
|
|
|
|
``request`` is an :class:`~django.http.HttpRequest` object. ``exception`` is an
|
|
``Exception`` object raised by the view function.
|
|
|
|
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 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,
|
|
the middleware classes above that middleware will not be called at all.
|
|
|
|
``__init__``
|
|
------------
|
|
|
|
Most middleware classes won't need an initializer since middleware classes are
|
|
essentially placeholders for the ``process_*`` methods. If you do need some
|
|
global state you may use ``__init__`` to set up. However, keep in mind a couple
|
|
of caveats:
|
|
|
|
* Django initializes your middleware without any arguments, so you can't
|
|
define ``__init__`` as requiring any arguments.
|
|
|
|
* Unlike the ``process_*`` methods which get called once per request,
|
|
``__init__`` gets called only *once*, when the Web server responds to the
|
|
first request.
|
|
|
|
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 :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove
|
|
that piece of middleware from the middleware process.
|
|
|
|
Guidelines
|
|
----------
|
|
|
|
* Middleware classes don't have to subclass anything.
|
|
|
|
* The middleware class can live anywhere on your Python path. All Django
|
|
cares about is that the :setting:`MIDDLEWARE_CLASSES` setting includes
|
|
the path to it.
|
|
|
|
* Feel free to look at :doc:`Django's available middleware
|
|
</ref/middleware>` for examples.
|
|
|
|
* If you write a middleware component that you think would be useful to
|
|
other people, contribute to the community! :doc:`Let us know
|
|
</internals/contributing/index>`, and we'll consider adding it to Django.
|