Spec-Zone.ru › Django 2.2

Средний уровень

Средний уровень — это фреймворк хуков для обработки запросов/ответов Django. Это лёгкая, низкоуровневая система «плагинов» для глобального изменения входных или выходных данных Django.

Каждый компонент среднего уровня отвечает за выполнение определённой функции. Например, Django включает компонент среднего уровня, AuthenticationMiddleware, который связывает пользователей с запросами, используя сессии.

Этот документ объясняет, как работает средний уровень, как его активировать и как написать собственный компонент среднего уровня. Django поставляется с некоторыми встроенными компонентами среднего уровня, которые можно использовать сразу. Они документированы в справке по встроенным компонентам среднего уровня.

Создание собственного компонента среднего уровня

Фабрика среднего уровня — это вызываемый объект, который принимает вызываемый объект get_response и возвращает компонент среднего уровня. Компонент среднего уровня — это вызываемый объект, который принимает запрос и возвращает ответ, как и представление.

Компонент среднего уровня может быть написан как функция, похожая на эту:

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

Или он может быть написан как класс, экземпляры которого вызываемы, как это:

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

Вызываемый объект get_response , предоставленный Django, может быть фактическим представлением (если это последний перечисленный компонент среднего уровня) или следующим компонентом среднего уровня в цепочке. Текущий компонент среднего уровня не нуждается в знании или понимании того, что это именно, а только в том, что это представляет то, что следует далее.

Вышеприведённое — это упрощённое представление — вызываемый объект get_response для последнего компонента среднего уровня в цепочке не будет фактическим представлением, а скорее методом-обёрткой от обработчика, который отвечает за применение среднего уровня представления, вызов представления с соответствующими аргументами URL и применение среднего уровня ответа шаблона и среднего уровня исключений.

Компоненты среднего уровня могут быть расположены в любом месте на вашем пути Python.

__init__(get_response)

Фабрики среднего уровня должны принимать аргумент get_response. Вы также можете инициализировать некоторое глобальное состояние для компонента среднего уровня. Имейте в виду несколько нюансов:

  • Django инициализирует ваш компонент среднего уровня только с аргументом get_response, поэтому вы не можете определить __init__() как требующий каких-либо других аргументов.
  • В отличие от метода __call__(), который вызывается один раз на запрос, __init__() вызывается только один раз, при запуске веб-сервера.

Отмечание компонента среднего уровня как неиспользуемого

Иногда полезно определить во время запуска, следует ли использовать компонент среднего уровня. В этих случаях метод __init__() вашего компонента среднего уровня может вызвать MiddlewareNotUsed. Тогда Django удалит этот компонент среднего уровня из процесса обработки среднего уровня и запишет сообщение отладки в логгер django.request, когда DEBUG равно True.

Активация среднего уровня

Чтобы активировать компонент среднего уровня, добавьте его в список MIDDLEWARE в ваших настройках Django.

В MIDDLEWARE каждый компонент среднего уровня представлен строкой: полным путём к классу или имени функции фабрики компонента среднего уровня. Например, вот значение по умолчанию, созданное django-admin startproject:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    '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',
]

Установка Django не требует никакого среднего уровня — MIDDLEWARE может быть пустым, если вам это нужно — но настоятельно рекомендуется, по крайней мере, использовать CommonMiddleware.

Порядок в MIDDLEWARE имеет значение, так как компонент среднего уровня может зависеть от других компонентов. Например, AuthenticationMiddleware хранит аутентифицированного пользователя в сессии; поэтому он должен выполняться после SessionMiddleware. См. Порядок компонентов среднего уровня, чтобы получить некоторые общие указания по порядку классов компонентов среднего уровня Django.

Порядок и слоирование компонентов среднего уровня

Во время фазы запроса, перед вызовом представления, Django применяет компоненты среднего уровня в порядке их определения в MIDDLEWARE, сверху вниз.

Можно представить это как луковицу: каждый класс компонента среднего уровня — это «слой», который оборачивает представление, которое находится в ядре луковицы. Если запрос проходит через все слои луковицы (каждый из них вызывает get_response для передачи запроса в следующий слой), до представления в ядре, ответ затем пройдёт через каждый слой (в обратном порядке) по пути наружу.

Если один из слоёв решит прервать выполнение и вернуть ответ, не вызывая его get_response, ни один из слоёв луковицы внутри этого слоя (включая представление) не увидит запрос или ответ. Ответ будет возвращён только через те же слои, через которые вошёл запрос.

Другие хуки компонентов среднего уровня

Помимо базового паттерна запроса/ответа компонента среднего уровня, описанного выше, вы можете добавить три других специальных метода в классы компонентов среднего уровня:

process_view()

process_view(request, view_func, view_args, view_kwargs)

request — это объект HttpRequest. view_func — это функция Python, которую собирается использовать Django. (Это фактическая функция, а не имя функции как строка.) view_args — это список позиционных аргументов, которые будут переданы представлению, а view_kwargs — это словарь ключевых аргументов, которые будут переданы представлению. Ни view_args, ни view_kwargs не включают первый аргумент представления (request).

process_view() вызывается незадолго до того, как Django вызовет представление.

Он должен вернуть либо None, либо объект HttpResponse. Если он возвращает None, Django продолжит обработку этого запроса, выполнив любые другие компоненты среднего уровня process_view() и затем соответствующее представление. Если он возвращает объект HttpResponse, Django не станет вызывать соответствующее представление; он применит компоненты среднего уровня ответа к этому объекту HttpResponse и вернёт результат.

Примечание

Доступ к request.POST внутри компонента среднего уровня перед запуском представления или в process_view() помешает любому представлению, выполняющемуся после компонента среднего уровня, выполнить изменение обработчиков загрузки для запроса, и это обычно следует избегать.

Класс CsrfViewMiddleware можно рассматривать как исключение, так как он предоставляет декораторы csrf_exempt() и csrf_protect(), которые позволяют представлениям явно управлять моментом выполнения проверки CSRF.

process_exception()

process_exception(request, exception)

request — это объект HttpRequest. exception — это объект Exception , вызванный функцией представления.

Django вызывает process_exception() при возникновении исключения в представлении. process_exception() должно вернуть либо None, либо объект HttpResponse. Если он возвращает объект HttpResponse, шаблон ответа и компоненты среднего уровня ответа будут применены, и полученный ответ будет возвращён в браузер. В противном случае срабатывает обработка исключений по умолчанию.

Опять же, компоненты среднего уровня выполняются в обратном порядке во время фазы ответа, что включает process_exception. Если компонент среднего уровня исключений возвращает ответ, методы process_exception классов компонентов среднего уровня выше этого компонента не будут вызываться вообще.

process_template_response()

process_template_response(request, response)

request — это объект HttpRequest. response — это объект TemplateResponse (или эквивалент), возвращаемый представлением Django или промежуточным ПО.

process_template_response() вызывается сразу после завершения выполнения представления, если экземпляр ответа имеет метод render(), указывающий, что это объект TemplateResponse или эквивалент.

Он должен вернуть объект ответа, реализующий метод render. Он может изменить переданный объект response, изменив response.template_name и response.context_data, или он может создать и вернуть новый объект TemplateResponse или эквивалент.

Вам не нужно явно рендерить ответы — ответы будут автоматически рендериться после вызова всех промежуточных ПО для обработки шаблонов.

Промежуточное ПО выполняется в обратном порядке во время фазы ответа, которая включает process_template_response().

Обработка потоковых ответов

В отличие от HttpResponse, StreamingHttpResponse не имеет атрибута content. В результате, промежуточное ПО больше не может предполагать, что все ответы будут иметь атрибут content. Если им нужен доступ к содержимому, они должны проверить наличие потокового ответа и скорректировать свое поведение соответственно:

if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)

Примечание

streaming_content следует предполагать слишком большим для хранения в памяти. Промежуточное ПО ответа может обернуть его в новый генератор, но не должно его потреблять. Обертка обычно реализуется следующим образом:

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)

Обработка исключений

Django автоматически преобразует исключения, поднятые представлением или промежуточным ПО, в соответствующий HTTP-ответ с кодом состояния ошибки. Определенные исключения преобразуются в коды состояния 4xx, а неизвестное исключение преобразуется в код состояния 500.

Это преобразование происходит до и после каждого промежуточного ПО (можно представить себе как тонкую пленку между каждым слоем лука), так что каждое промежуточное ПО всегда может полагаться на получение некоторого вида HTTP-ответа от вызова его get_response вызываемого объекта. Промежуточному ПО не нужно беспокоиться о обертывании своего вызова get_response в try/except и обработке исключения, которое может быть поднято последующим промежуточным ПО или представлением. Даже если следующее промежуточное ПО в цепочке поднимет исключение Http404, например, ваше промежуточное ПО не увидит это исключение; вместо этого оно получит объект HttpResponse с кодом состояния status_code 404.

Модернизация промежуточного ПО по старой схеме (до Django 1.10)

class django.utils.deprecation.MiddlewareMixin

Django предоставляет django.utils.deprecation.MiddlewareMixin для облегчения создания классов промежуточного ПО, совместимых как с MIDDLEWARE, так и со старой схемой MIDDLEWARE_CLASSES. Все классы промежуточного ПО, включенные в Django, совместимы с обеими настройками.

Mixin предоставляет метод __init__(), который принимает необязательный аргумент get_response и сохраняет его в self.get_response.

Метод __call__():

  1. Вызывает self.process_request(request) (если определен).
  2. Вызывает self.get_response(request) для получения ответа от последующих промежуточных ПО и представления.
  3. Вызывает self.process_response(request, response) (если определен).
  4. Возвращает ответ.

Если используется со схемой MIDDLEWARE_CLASSES, метод __call__() никогда не будет использован; Django вызывает process_request() и process_response() напрямую.

В большинстве случаев наследование от этого mixin будет достаточно, чтобы сделать промежуточное ПО старой схемы совместимым с новой системой с достаточной обратной совместимостью. Новые семантики краткосрочного обрыва будут безвредны или даже полезны для существующего промежуточного ПО. В некоторых случаях классу промежуточного ПО могут потребоваться некоторые изменения для адаптации к новым семантикам.

Вот различия в поведении между использованием MIDDLEWARE и MIDDLEWARE_CLASSES:

  1. В старой схеме каждый промежуточное ПО всегда будет вызывать метод process_response, даже если предыдущее промежуточное ПО сократило обработку, вернув ответ из своего метода process_request. В новой схеме промежуточное ПО ведет себя как слои лука: слои, через которые проходит ответ при выходе, — это те же слои, что и те, которые видели запрос при входе. Если промежуточное ПО сокращает обработку, только это промежуточное ПО и предшествующие ему в MIDDLEWARE увидят ответ.
  2. В старой схеме process_exception применяется к исключениям, поднятым из метода промежуточного ПО process_request . В новой схеме process_exception применяется только к исключениям, поднятым из представления (или из метода render объекта TemplateResponse). Исключение, поднятое из промежуточного ПО, преобразуется в соответствующий HTTP-ответ и затем передаётся следующему промежуточному ПО.
  3. В старой схеме, если метод process_response поднимет исключение, методы process_response всех предыдущих промежуточных ПО будут пропущены, и всегда будет возвращён HTTP-ответ 500 Internal Server Error (даже если поднятое исключение было, например, Http404). В новой схеме исключение, поднятое из промежуточного ПО, немедленно преобразуется в соответствующий HTTP-ответ, и затем следующее промежуточное ПО увидит этот ответ. Промежуточные ПО никогда не пропускаются из-за поднятия исключения промежуточным ПО.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/topics/http/middleware/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API