mirror of
				https://github.com/django/django.git
				synced 2025-10-28 16:16:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			292 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			292 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.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
 | |
| 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`.
 | |
| 
 | |
| 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(self, 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(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 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(self, 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(self, 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
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| .. versionchanged:: 1.5
 | |
| 
 | |
|     ``response`` may also be an :class:`~django.http.StreamingHttpResponse`
 | |
|     object.
 | |
| 
 | |
| 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(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 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.
 |