Среднесвязь
Среднесвязь — это фреймворк хуков для обработки запросов/ответов в 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 продолжит обработку этого запроса, выполнив остальные компоненты среднесвязи, обрабатывающие запросы, затем компоненты, обрабатывающие исключения, и, наконец, соответствующее представление. Если возвращается объект 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 продолжит обработку запроса, выполнив другие компоненты среднесвязи, обрабатывающие представления, и затем соответствующее представление. Если возвращается объект HttpResponse, Django не будет вызывать другие компоненты среднесвязи, обрабатывающие представления или исключения, или соответствующее представление; он применит компоненты среднесвязи, обрабатывающие ответы, к этому объекту HttpResponse и вернет результат.
Примечание
Доступ к request.POST внутри среднесвязи из 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() того же класса промежуточного ПО были пропущены (потому что метод промежуточного ПО, вызваный ранее, возвратил объект HttpResponse). В частности, это означает, что ваш метод process_response() не может полагаться на настройку, выполненную в process_request().
Наконец, помните, что во время фазы ответа промежуточное ПО применяется в обратном порядке, сверху вниз. Это означает, что классы, определённые в конце MIDDLEWARE_CLASSES, будут выполняться первыми.
Работа с потоковыми ответами
В отличие от 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)
process_exception()
-
process_exception(request, exception)
request — это объект HttpRequest. exception — это объект Exception , поднятый функцией представления.
Django вызывает process_exception() , когда представление вызывает исключение. process_exception() должен вернуть либо None , либо объект HttpResponse. Если он возвращает объект HttpResponse, шаблонный ответ и промежуточное ПО ответа будут применены, и полученный ответ будет возвращён браузеру. В противном случае срабатывает стандартная обработка исключений.
Опять же, промежуточное ПО выполняется в обратном порядке во время фазы ответа, включая process_exception. Если промежуточное ПО обработки исключений возвращает ответ, классы промежуточного ПО, расположенные выше этого промежуточного ПО, вообще не будут вызываться.
__init__()
Большинству классов промежуточного ПО не потребуется инициализатор, так как классы промежуточного ПО в основном являются заглушками для методов process_*. Если вам действительно нужна некоторая глобальная переменная, вы можете использовать __init__ для её настройки. Однако имейте в виду несколько замечаний:
- Django инициализирует ваше промежуточное ПО без каких-либо аргументов, поэтому вы не можете определить
__init__как требующее каких-либо аргументов. - В отличие от методов
process_*, которые вызываются один раз на запрос,__init__вызывается только один раз, когда веб-сервер отвечает на первый запрос.
Отметка промежуточного ПО как неиспользуемого
Иногда полезно определить во время выполнения, должно ли использоваться какой-либо фрагмент промежуточного ПО. В этих случаях метод __init__ вашего промежуточного ПО может вызвать django.core.exceptions.MiddlewareNotUsed. Django затем удалит этот фрагмент промежуточного ПО из процесса промежуточного ПО, а сообщение отладки будет записано в логгер django.request , когда DEBUG будет установлено в True.
Ранее исключения MiddlewareNotUsed не регистрировались.
Руководящие принципы
- Классы промежуточного ПО не обязаны ни от чего наследоваться.
- Класс промежуточного ПО может находиться в любом месте на вашем пути Python. Всё, что заботит Django, это то, что в настройке
MIDDLEWARE_CLASSESуказан путь к нему. - Не стесняйтесь обращаться к документации Django по доступному промежуточному ПО для примеров.
- Если вы напишете компонент промежуточного ПО, который, по вашему мнению, может быть полезен другим людям, внесите вклад в сообщество! Дайте нам знать, и мы рассмотрим возможность добавления его в Django.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.9/topics/http/middleware/