Средний слой
Средний слой — это фреймворк хуков в обработке запросов/ответов Django. Это лёгкая, низкоуровневая система «плагинов» для глобального изменения входных или выходных данных Django.
Каждый компонент среднего слоя отвечает за выполнение определённой функции. Например, Django включает компонент среднего слоя, AuthenticationMiddleware, который ассоциирует пользователей с запросами, используя сессии.
Этот документ объясняет, как работает средний слой, как активировать средний слой и как написать собственный средний слой. Django поставляется с некоторыми встроенными компонентами среднего слоя, которые вы можете использовать сразу. Они документированы в справочнике встроенных компонентов среднего слоя.
Активация среднего слоя
Чтобы активировать компонент среднего слоя, добавьте его в кортеж MIDDLEWARE_CLASSES в ваших настройках Django.
В MIDDLEWARE_CLASSES, каждый компонент среднего слоя представлен строкой: полным путём в Python до имени класса среднего слоя. Например, вот значение по умолчанию, созданное django-admin 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',
)
Установке Django не требуется какой-либо средний слой — MIDDLEWARE_CLASSES может быть пустым, если вы этого хотите — но настоятельно рекомендуется хотя бы использовать CommonMiddleware.
Порядок в MIDDLEWARE_CLASSES важен, потому что один средний слой может зависеть от другого. Например, AuthenticationMiddleware сохраняет аутентифицированного пользователя в сессии; поэтому он должен выполняться после SessionMiddleware. См. Порядок компонентов среднего слоя для некоторых общих подсказок по порядку классов компонентов среднего слоя Django.
Хуки и порядок приложения
Во время фазы запроса, до вызова представления, Django применяет компоненты среднего слоя в порядке их определения в MIDDLEWARE_CLASSES, сверху вниз. Доступны два хука:
Во время фазы ответа, после вызова представления, компоненты среднего слоя применяются в обратном порядке, снизу вверх. Доступны три хука:
-
process_exception()(только если представление вызвало исключение) -
process_template_response()(только для ответов шаблонов) process_response()
Если вы предпочитаете, вы также можете представить это как луковицу: каждый класс среднего слоя — это «слой», который оборачивает представление.
Поведение каждого хука описано ниже.
Написание собственного среднего слоя
Написание собственного среднего слоя просто. Каждый компонент среднего слоя — это отдельный класс Python, который определяет один или несколько из следующих методов:
process_request
-
process_request(request)
request — это объект HttpRequest.
process_request() вызывается при каждом запросе, до того, как Django определит, какое представление выполнить.
Он должен возвращать либо None или объект HttpResponse. Если он возвращает None, Django продолжит обработку этого запроса, выполнив любые другие компоненты process_request() среднего слоя, затем process_view() компоненты среднего слоя и, наконец, соответствующее представление. Если он возвращает объект HttpResponse, Django не будет беспокоиться о вызове других компонентов среднего слоя запроса, представления или исключений, или соответствующего представления; он применит компоненты среднего слоя ответа к этому HttpResponse и вернёт результат.
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 или request.REQUEST внутри среднего слоя из process_request или process_view помешает любому представлению, выполняющемуся после среднего слоя, изменить обработчики загрузки запроса, и обычно следует избегать этого.
Класс CsrfViewMiddleware можно рассматривать как исключение, так как он предоставляет декораторы csrf_exempt() и csrf_protect(), которые позволяют представлениям явно контролировать, когда должна происходить проверка CSRF.
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().
process_response
-
process_response(request, response)
request — это объект HttpRequest. response — это объект HttpResponse или StreamingHttpResponse, возвращённый представлением Django или компонентом среднего слоя.
process_response() вызывается для всех ответов перед их отправкой в браузер.
Он должен вернуть объект HttpResponse или StreamingHttpResponse. Он может изменить переданный response, или он может создать и вернуть совершенно новый объект HttpResponse или StreamingHttpResponse.
В отличие от методов process_request() и process_view(), метод process_response() всегда вызывается, даже если методы process_request() и process_view() того же класса middleware были пропущены (потому что предыдущий метод middleware вернул объект HttpResponse). В частности, это означает, что ваш метод process_response() не может полагаться на настройки, выполненные в process_request().
Наконец, помните, что во время фазы ответа middleware применяются в обратном порядке, снизу вверх. Это означает, что классы, определённые в конце MIDDLEWARE_CLASSES, будут выполнены первыми.
Работа с потоковыми ответами
В отличие от HttpResponse, StreamingHttpResponse не имеет атрибута content. В результате middleware больше не могут предполагать, что все ответы будут иметь атрибут content. Если им нужен доступ к содержимому, они должны проверить, является ли ответ потоковым, и соответствующим образом скорректировать свое поведение:
if response.streaming:
response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
response.content = alter_content(response.content)
Примечание
streaming_content следует считать слишком большим для хранения в памяти. Middleware для ответа может обернуть его в новый генератор, но не должен его потреблять. Обычно обертывание реализуется следующим образом:
def wrap_streaming_content(content):
for chunk in content:
yield alter_content(chunk)
process_exception
-
process_exception(request, exception)
request — это объект HttpRequest. exception — это объект Exception, поднятый функцией представления.
Django вызывает process_exception() при возникновении исключения в функции представления. process_exception() должен вернуть либо None, либо объект HttpResponse. Если он возвращает объект HttpResponse, то будут применены шаблонный ответ и middleware для ответа, а полученный ответ будет возвращен браузеру. В противном случае срабатывает стандартная обработка исключений.
Опять же, middleware запускаются в обратном порядке во время фазы ответа, что включает в себя process_exception. Если middleware для обработки исключений возвращает ответ, то классы middleware, расположенные выше, вообще не будут вызваны.
__init__
Большинству классов middleware не нужен инициализатор, так как они по сути являются заглушками для методов process_*. Если вам нужна глобальная переменная, вы можете использовать __init__ для её инициализации. Однако имейте в виду несколько ограничений:
- Django инициализирует ваш middleware без каких-либо аргументов, поэтому вы не можете определить
__init__как требующий аргументов. - В отличие от методов
process_*, которые вызываются один раз на запрос,__init__вызывается только один раз, когда веб-сервер отвечает на первый запрос.
Отмечание middleware как неиспользуемого
Иногда полезно определить во время выполнения, нужно ли использовать компонент middleware. В этих случаях метод __init__ вашего middleware может поднять исключение django.core.exceptions.MiddlewareNotUsed. Django затем удалит этот компонент middleware из процесса middleware, и сообщение об ошибке будет записано в журнал django.request логгер, когда DEBUG установлен на True.
Ранее исключения MiddlewareNotUsed не записывались в лог.
Руководство
- Классы middleware не обязаны быть подклассами чего-либо.
- Класс middleware может находиться в любом месте на вашем пути Python. Django интересует только то, что настройка
MIDDLEWARE_CLASSESвключает путь к нему. - Пожалуйста, изучите доступные middleware Django для примеров.
- Если вы написали компонент middleware, который, по вашему мнению, может быть полезен другим людям, внесите свой вклад в сообщество! Дайте нам знать, и мы рассмотрим возможность добавления его в Django.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.8/topics/http/middleware/