Дополнительные процессоры Django

Опубликовал: Четверг, Февраль 16, 2012 в категории Django | Пока нет комментариев

Иногда возникает необходимость реализовать дополнительную обработку всех без исключения запросов, обслуживаемых Django. Такая обработка может понадобиться, чтобы модифицировать запрос перед передачей его в функцию представления, записать в журнал какие- нибудь сведения о запросе для отладки и т. д.

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

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

•      Все средства управления сеансами и пользователями, рассмотренные в главе 14, в своей работе опираются на дополнительные процессоры (точнее, процессоры открывают представлениям доступ к объектам request.session и request.user).

•      Механизм кэширования на уровне сайта, рассмотренный в главе 15, - это не что иное, как дополнительный процессор, который обходит вызов функции представления, если ответ уже находится в кэше.

•      Плоские страницы, объекты переадресации и реализация механизма защиты от CSRF-атак (глава 16) также реализованы с помощью дополнительных процессоров.

В этой главе мы детально рассмотрим принципы работы дополнительных процессоров и покажем, как можно написать такой процессор самостоятельно.

Что такое дополнительный процессор?

Начнем с очень простого примера.

На высоконагруженных сайтах фреймворк Django часто развертывают за балансировщиком нагрузки (см. главу 12). Это может вызвать некоторые затруднения, одно из которых заключается в том, что теперь в роли IP-адреса клиента (request.META[,'REMOTE_IP"]) выступает адрес балансировщика, а не действительного клиента, отправившего запрос. Балансировщики нагрузки решают эту проблему, добавляя в исходный запрос специальный HTTP-заголовок X-Forwarded-For, где указывается IP-адрес истинного клиента.

Приведем пример простого дополнительного процессора, который позволяет сайтам, находящимся за прокси-сервером, выполняющим балансировку, находить истинный IP-адрес там, где ему положено быть, - в заголовке META["REMOTE_ADDR"]:

class SetRemoteAddrFromForwardedFor(object): def process_request(self, request): try:

real_ip = request.META['HTTP_X_FORWARDED_FOR,] except KeyError:

pass else:

tt HTTP_X_FORWARDED_FOR может быть списком IP-адресов, tt разделенных запятой. Берем первый из них. real_ip = real_ip.split( V’)[0] request.МЕТА['REMOTE_ADDR'] = real_ip

Примечание ——————————————————————————

Хотя HTTP-заголовок на самом деле называется X-Forwarded-For, Django предоставляет к нему доступ по имени request.META['HTTP_X_FORWARDED_FOR']. Все заголовки в запросе, за исключением content-length и content-type, преобразуются в ключи словаря request.МЕТА путем преобразования символов в верхний регистр, замены дефисов символами подчеркивания и добавления префикса НТТР_.

Если установить этот дополнительный процессор (см. следующий раздел), то значение заголовка X-Forwarded-For в любом запросе автоматически будет записываться в элемент словаря request.META['REMOTE_ADDR']. В результате приложению Django будет безразлично, стоит перед ним балансирующий прокси-сервер или нет; оно просто будет обращаться к элементу request.МЕТА['REMOTE_ADDR' ] и действовать так, как если бы никакого прокси-сервера не существовало.

На самом деле такая потребность возникает настолько часто, что этот дополнительный процессор уже встроен в Django. Он находится в пакете django.middleware.http, и мы еще вернемся к нему ниже.

Установка дополнительных процессоров

Если вы читали книгу подряд, то уже встречались с многочисленными примерами установки дополнительных процессоров; они были необходимы для многих приложений, описанных в предыдущих главах. Тем не менее для полноты картины расскажем, как производится установка.

Чтобы активировать дополнительный процессор, добавьте его в кортеж MIDDLEWARE_CLASSES в файле параметров. В этом кортеже каждый процессор представлен строкой, содержащей полный путь Python к имени соответствующего класса. Вот, например, как выглядит параметр MIDDLEWARE_CLASSES в проекте, который по умолчанию создается командой django-admin.py startproject:

MIDDLEWARE_CLASSES = (

‘django.middleware.common.CommonMiddleware’, ‘django.contrib.sessions.middleware.SessionMiddleware’, ‘django.contrib.auth.middleware.AuthenticationMiddleware’ ,

)

Для работы самого фреймворка Django никакие дополнительные процессоры не нужны, то есть кортеж MIDDLEWARE_CLASSES может быть пустым. Однако мы рекомендуем активировать хотя бы процессор CommonMiddleware, который опишем чуть ниже.

Порядок следования процессоров имеет важное значение. На этапах получения запроса и работы представления Django вызывает дополнительные процессоры в том порядке, в котором они перечислены в MIDDLEWARE_CLASSES, а на этапах формирования ответа и обработки исключений - в обратном порядке. Таким образом, дополнительные процессоры - это своего рода «обертка» вокруг функции представления: при обработке запроса список процессоров просматривается сверху вниз, а при формировании ответа - снизу вверх.

Методы дополнительных процессоров

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

Инициализация:_ init_ (self)

Метод_______ init__ () применяется для инициализации класса дополнительного процессора.

Из соображений производительности каждый активированный класс процессора инициализируется только один раз на протяжении времени жизни серверного процесса. Это означает, что метод________________________________ init__ () вызывается однократно - на этапе инициализации сервера, - а не для каждого запроса.

Обычно метод_______ init__ () реализуют, чтобы проверить, а нужен ли вообще данный процессор. Если init () возбудит исключение django.

core.exceptions.MiddlewareNotUsed, то Django удалит процессор из списка вызываемых. Эту возможность можно использовать, чтобы проверить, установлено ли программное обеспечение, необходимое дополнительному процессору, или узнать, работает ли сервер в режиме отладки, или выполнить аналогичные функции, смотря по обстоятельствам.

Если в классе процессора определен метод__________ init__ (), то он не должен

принимать никаких аргументов, кроме self.

Препроцессор запроса: process_request(self, request)

Этот метод вызывается сразу после получения запроса - еще до того, как Django проанализирует URL и определит, какое представление следует вызвать. Ему передается объект HttpRequest, который он может модифицировать произвольным образом.

Метод process_request() должен вернуть либо значение None, либо объект HttpResponse.

•       При получении значения None Django продолжит обработку запроса, вызывая по-порядку все остальные дополнительные процессоры, а затем требуемое представление.

•       При получении объекта HttpResponse Django не станет вызывать больше никаких дополнительных процессоров или представление, а сразу вернет этот объект клиенту.

Препроцессор представления: process_view(self, request, view, args, kwargs)

Этот метод вызывается после препроцессора запроса и после того, как Django определит, какое представление следует вызвать, но до вызова этого представления.

Ему передаются аргументы, перечисленные в табл. 17.1.

Таблица 17.1. Аргументы, передаваемые process_view()

Аргумент

Пояснение

request

Объект HttpRequest.

view

Функция Python, которую Django вызовет для обработки запроса. Это сам объект функции, а не ее имя в виде строки.

args

Список позиционных аргументов, передаваемых представлению, не включая аргумент request (который всегда передается представлению первым).

kwargs

Словарь именованных аргументов, передаваемый представлению.

Как и process_request(), метод process_view() должен вернуть значение

None или объект HttpResponse.

•       При получении значения None Django продолжит обработку запроса, вызывая по порядку все остальные дополнительные процессоры, а затем требуемое представление.

•       При получении объекта HttpResponse Django не станет вызывать больше никаких дополнительных процессоров или представление, а сразу вернет этот объект клиенту.

Постпроцессор ответа: process_response(self, request, response)

Этот метод вызывается после того, как функция представления отработала и сконструировала ответ. Процессор может модифицировать содержимое ответа. Очевидный пример - сжатие HTML-содержимого применением алгоритма gzip.

Параметры метода не нуждаются в пространных пояснениях: request - объект запроса, response - объект ответа, возвращаемый представлением.

В отличие от препроцессоров запроса и представления, которые могут возвращать значение None, метод process_response() обязан вернуть объект HttpResponse. Это может быть тот самый объект, который был ему передан (возможно, модифицированный), или совершенно новый.

Постпроцессор обработки исключений: process_exception(self, request, exception)

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

В качестве параметров функции передаются все тот же объект request и объект exception - то самое исключение, которое возбудила функция представления.

Метод process_exception() должен вернуть значение None или объект

HttpResponse.

•       При получении значения None Django продолжит обработку запроса, применяя встроенный механизм обработки исключений.

•       При получении объекта HttpResponse Django вернет именно его в обход встроенного механизма обработки исключений.

Примечание ———————————————————————————-

В комплект поставки Django входит ряд дополнительных процессоров (они рассматриваются в следующем разделе), которые могут служить неплохими примерами. Ознакомившись с их реализацией, вы получите представление о колоссальных возможностях этого механизма. На вики-странице Django по адресу http://code.djangoproject.com/wiki/ContributedMiddleware приводится немало примеров, предложенных сообществом.

Источник: Головатый А., Каплан-Мосс Дж. Django. Подробное руководство, 2-е издание. - Пер. с англ. - СПб.: Символ- Плюс, 2010. - 560 е., ил.

Похожие посты:

Комментировать

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>