Spec-Zone.ru › Django 2.0

Среднее ПО

Среднее ПО — это фреймворк хуков в обработке запросов/ответов 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 каждый компонент среднего ПО представлен строкой: полным путём Python к классу или имени функции фабрики среднего ПО. Например, вот значение по умолчанию, созданное 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 продолжит обработку этого запроса, выполнит любое другое среднее ПО и, затем, соответствующее представление. Если он возвращает объект 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, совместимы с обоими параметрами.

Миксин предоставляет метод __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() напрямую.

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

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

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

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

Spec-Zone.ru

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