181 lines
7.5 KiB
Plaintext
181 lines
7.5 KiB
Plaintext
.. _topics-http-middleware:
|
|
|
|
==========
|
|
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.
|
|
|
|
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.
|
|
|
|
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 :ref:`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>`::
|
|
|
|
MIDDLEWARE_CLASSES = (
|
|
'django.middleware.common.CommonMiddleware',
|
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
'django.middleware.csrf.CsrfViewMiddleware',
|
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
)
|
|
|
|
During the request phases (:meth:`process_request` and :meth:`process_view`
|
|
middleware), Django applies middleware in the order it's defined in
|
|
:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases
|
|
(:meth:`process_response` and :meth:`process_exception` middleware), the
|
|
classes are applied in reverse order, from the bottom up. You can think of it
|
|
like an onion: each middleware class is a "layer" that wraps the view:
|
|
|
|
.. image:: _images/middleware.png
|
|
:width: 502
|
|
:height: 417
|
|
:alt: Middleware application order.
|
|
|
|
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`.
|
|
|
|
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(self, request)
|
|
|
|
``request`` is an :class:`~django.http.HttpRequest` object. This method 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.
|
|
|
|
.. _view-middleware:
|
|
|
|
``process_view``
|
|
----------------
|
|
|
|
.. method:: process_view(self, 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 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.
|
|
|
|
.. _response-middleware:
|
|
|
|
``process_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.
|
|
|
|
``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`.
|
|
|
|
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.
|
|
|
|
.. _exception-middleware:
|
|
|
|
``process_exception``
|
|
---------------------
|
|
|
|
.. method:: process_exception(self, 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 response will be 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 return 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 starts up.
|
|
|
|
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.
|
|
|
|
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 :ref:`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! :ref:`Let us know
|
|
<internals-contributing>`, and we'll consider adding it to Django.
|