123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- ==========
- 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` 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 value created by :djadmin:`django-admin startproject
- <startproject>`::
- MIDDLEWARE_CLASSES = [
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
- '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>` 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 and a debug message will
- be logged to the ``django.request`` logger when :setting:`DEBUG` is set to
- ``True``.
- .. versionchanged:: 1.8
- Previously, :exc:`~django.core.exceptions.MiddlewareNotUsed` exceptions
- weren't logged.
- 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.
|