diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2020-02-12 15:15:00 -0700 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2020-03-18 19:59:12 +0100 |
| commit | fc0fa72ff4cdbf5861a366e31cb8bbacd44da22d (patch) | |
| tree | d419ce531586808b0a111664907b859cb6d22862 /docs/topics/http/middleware.txt | |
| parent | 3f7e4b16bf58f99c71570ba75dc97db8265071be (diff) | |
Fixed #31224 -- Added support for asynchronous views and middleware.
This implements support for asynchronous views, asynchronous tests,
asynchronous middleware, and an asynchronous test client.
Diffstat (limited to 'docs/topics/http/middleware.txt')
| -rw-r--r-- | docs/topics/http/middleware.txt | 87 |
1 files changed, 85 insertions, 2 deletions
diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt index d72d39de5e..3fe00b947f 100644 --- a/docs/topics/http/middleware.txt +++ b/docs/topics/http/middleware.txt @@ -71,6 +71,10 @@ method from the handler which takes care of applying :ref:`view middleware applying :ref:`template-response <template-response-middleware>` and :ref:`exception <exception-middleware>` middleware. +Middleware can either support only synchronous Python (the default), only +asynchronous Python, or both. See :ref:`async-middleware` for details of how to +advertise what you support, and know what kind of request you are getting. + Middleware can live anywhere on your Python path. ``__init__(get_response)`` @@ -282,6 +286,81 @@ if the very next middleware in the chain raises an that exception; instead it will get an :class:`~django.http.HttpResponse` object with a :attr:`~django.http.HttpResponse.status_code` of 404. +.. _async-middleware: + +Asynchronous support +==================== + +.. versionadded:: 3.1 + +Middleware can support any combination of synchronous and asynchronous +requests. Django will adapt requests to fit the middleware's requirements if it +cannot support both, but at a performance penalty. + +By default, Django assumes that your middleware is capable of handling only +synchronous requests. To change these assumptions, set the following attributes +on your middleware factory function or class: + +* ``sync_capable`` is a boolean indicating if the middleware can handle + synchronous requests. Defaults to ``True``. + +* ``async_capable`` is a boolean indicating if the middleware can handle + asynchronous requests. Defaults to ``False``. + +If your middleware has both ``sync_capable = True`` and +``async_capable = True``, then Django will pass it the request in whatever form +it is currently in. You can work out what type of request you have by seeing +if the ``get_response`` object you are passed is a coroutine function or not +(using :py:func:`asyncio.iscoroutinefunction`). + +The ``django.utils.decorators`` module contains +:func:`~django.utils.decorators.sync_only_middleware`, +:func:`~django.utils.decorators.async_only_middleware`, and +:func:`~django.utils.decorators.sync_and_async_middleware` decorators that +allow you to apply these flags to middleware factory functions. + +The returned callable must match the sync or async nature of the +``get_response`` method. If you have an asynchronous ``get_response``, you must +return a coroutine function (``async def``). + +``process_view``, ``process_template_response`` and ``process_exception`` +methods, if they are provided, should also be adapted to match the sync/async +mode. However, Django will individually adapt them as required if you do not, +at an additional performance penalty. + +Here's an example of how to detect and adapt your middleware if it supports +both:: + + import asyncio + from django.utils.decorators import sync_and_async_middleware + + @sync_and_async_middleware + def simple_middleware(get_response): + # One-time configuration and initialization goes here. + if asyncio.iscoroutinefunction(get_response): + async def middleware(request): + # Do something here! + response = await get_response(request) + return response + + else: + def middleware(request): + # Do something here! + response = get_response(request) + return response + + return middleware + +.. note:: + + If you declare a hybrid middleware that supports both synchronous and + asynchronous calls, the kind of call you get may not match the underlying + view. Django will optimize the middleware call stack to have as few + sync/async transitions as possible. + + Thus, even if you are wrapping an async view, you may be called in sync + mode if there is other, synchronous middleware between you and the view. + .. _upgrading-middleware: Upgrading pre-Django 1.10-style middleware @@ -292,8 +371,8 @@ Upgrading pre-Django 1.10-style middleware Django provides ``django.utils.deprecation.MiddlewareMixin`` to ease creating middleware classes that are compatible with both :setting:`MIDDLEWARE` and the -old ``MIDDLEWARE_CLASSES``. All middleware classes included with Django -are compatible with both settings. +old ``MIDDLEWARE_CLASSES``, and support synchronous and asynchronous requests. +All middleware classes included with Django are compatible with both settings. The mixin provides an ``__init__()`` method that requires a ``get_response`` argument and stores it in ``self.get_response``. @@ -345,3 +424,7 @@ These are the behavioral differences between using :setting:`MIDDLEWARE` and HTTP response, and then the next middleware in line will see that response. Middleware are never skipped due to a middleware raising an exception. + +.. versionchanged:: 3.1 + + Support for asynchronous requests was added to the ``MiddlewareMixin``. |
