Django содержит “диспетчер сигналов”, который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определенным
о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.
Django предоставляет набор встроенных сигналов, которые позволяют пользовательскому коду получать уведомление от Django об определенных событиях. Эти сигналы включают в себя некоторые полезные уведомления:
Полный список этих сигналов, а также описание каждого сигнала, см. в
; см. ниже.
Прослушивание сигналов
Для того, чтобы принять сигнал, Вам необходимо с помощью метода
Signal.connect() зарегистрировать функцию
receiver, которая вызывается, когда сигнал послан:
-
Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None])
Давайте посмотрим, как это работает, зарегистрировав сигнал
request_finished, который вызывается после завершения выполнения HTTP запроса.
Функции-получатели
Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом следующего вида:
Заметьте, что функция принимает аргумент
sender, а также аргументы (
**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.
Отправителей мы рассмотрим
чуть позже, а сейчас обратите внимание на аргументы
**kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал
request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде
my_callback(sender).
Это было бы неверно – на самом деле, Django выдаст ошибку, если Вы это сделаете. Так произойдет, потому что при любом вызове аргументы могут быть добавлены к сигналу и получатель должен быть в состоянии обработать эти новые аргументы.
Регистрация функции-получателя
Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:
Кроме того, вы можете использовать декоратор
receiver при определении вашего получателя:
Теперь наша функция
my_callback будет вызываться каждый раз, когда запрос завершается.
Декоратор
receiver был добавлен в Django 1.3.
Сигналы, получаемые от определенных отправителей.
Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определенное подмножество этих сигналов. Например, рассмотрим
django.db.models.signals.pre_save - сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:
В этих случаях Вы можете получать только сигналы, посыланные определенными отправителями. В случае
django.db.models.signals.pre_save отправитель будет сохраняемой моделью некторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:
Функция
my_handler будет вызвана только при сохранении объекта класса
MyModel.
Отправителями различных сигналов могут быть различные различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к
документации по встроенным сигналам.
Предотвращение дублирования сигналов
В некоторых случаях модуль, в котором Вы подключаете сигналы, может быть импортирован несколько раз. Это может привести к тому, что получатель сигнала будет зарегистрирован несколько раз, и таким образом, вызов сигнала произойдет несколько раз при наступлении одного и того же события.
Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдет любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.
Создание и посылка сигналов.
Вы может создавать свои собственные сигналы в Ваших приложениях.
Создание сигналов
-
class Signal([providing_args=list])
Все сигналы являются экземплярами класса
django.dispatch.Signal, где
providing_args - список названий аргументов сигнала, которые будут доступны слушателям.
Например:
Это объявление сигнала
pizza_done, который предоставит получателям аргументы
toppings и
size.
Вы можете задать в этом списке аргументов любые значения передаваемых параметров.
Отправка сигналов
В Django существует два способа отправки сигналов.
-
Signal.send(sender, **kwargs)
-
Signal.send_robust(sender, **kwargs)
Для отправки сигнала необходимо вызвать
Signal.send() или
Signal.send_robust(). Вы обязательно должны указать аргумент
sender, кроме того можно указать сколько угодно других именованных аргументов.
Например, вот как может выглядать отправка сигнала
pizza_done.
И
send(), и
send_robust() возвращают список кортежей пар
[(receiver, response), ... ]. Каждый кортеж содержит вызываемую функцию и ее ответ.
send() отличается от
send_robust() способом обработки исключений, генерируемых функцией-получателем.
send() не ловит никаких исключений, сгенерированных в получателе, позволяя исключению проваливаться дальше. Таким образом, не все получатели могут получить сигнал при возникновении ошибки.
send_robust() перехватывает все ошибки, наследуемые от класса
Exception языка Python, и гарантирует, что сигнал дойдет до всех получателей. Если произойдет ошибка в одном из них, экземпляр исключения будет помещен в response в кортеже, который соответствует вызываемой функции.
Выключение сигнала
-
Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])
Чтобы отключить получатель от сигнала, назовите
Signal.disconnect(). Аргументы те же, что и у
Signal.connect().
В аргументе
receiver указывается получатель, который должен перестать получать сигнал.
receiver может быть
None если для идентификации получателя используется
dispatch_uid.