Разное

Сигналы django: Сигналы — Документация Django 1.9

Содержание

Сигналы — Документация Django 1.9

Django содержит “диспетчер сигналов”, который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определённым отправителям уведомлять некоторый набор получателей о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.

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

Вы можете также определять и посылать свои собственные сигналы; см. ниже.

Прослушивание сигналов

Для того, чтобы принять сигнал, Вам необходимо с помощью метода Signal.connect() зарегистрировать функцию receiver, которая вызывается, когда сигнал послан:

Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)
Параметры:
  • receiver – Функция, которая будет привязана к этому сигналу. Смотрите Функции-получатели.
  • sender – Указывает конкретного отправителя. Смотрите Сигналы, получаемые от определённых отправителей..
  • weak – Django сохраняет обработчики сигналов используя слабые ссылки(weak references). Поэтому, если функция-обработчик является локальной функцией, сборщик мусора может удалить ее. Чтобы избежать этого, передайте weak=False в connect().
  • dispatch_uid – Уникальный идентификатор получателя сигнала. На случай, если назначение обработчика может вызываться несколько раз. Смотрите Предотвращение дублирования сигналов.

Давайте посмотрим, как это работает, зарегистрировав сигнал request_finished, который вызывается после завершения выполнения HTTP запроса.

Функции-получатели

Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом:

def my_callback(sender, **kwargs):
    print("Request finished!")

Заметьте, что функция принимает аргумент sender, а также аргументы (**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.

Отправителей мы рассмотрим чуть позже, а сейчас обратите внимание на аргументы **kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде my_callback(sender).

Это было бы неверно – на самом деле, Django выдаст ошибку, если Вы это сделаете. Так произойдёт, потому что при любом вызове аргументы могут быть добавлены к сигналу и получатель должен быть в состоянии обработать эти новые аргументы.

Регистрация функции-получателя

Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:

from django.core.signals import request_finished

request_finished.connect(my_callback)

Кроме того, вы можете использовать декоратор receiver() при определении вашего получателя:

receiver(signal)
Параметры:signal – Сигнал или список обрабатываемых сигналов.

Вот как можно использовать декоратор:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

Теперь наша функция my_callback будет вызываться каждый раз, когда запрос завершается.

Куда положить этот код?

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

На практике, обработчики сигналов лежат в модуле signals приложения, к которому они относятся. Подключение к сигналам выполняется в методе ready() конфигурационного класса приложения. При использовании декоратора receiver() просто импортируйте модуль signals в ready().

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

Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определённое подмножество этих сигналов. Например, рассмотрим django.db.models.signals.pre_save — сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:

В этих случаях Вы можете получать только сигналы, посланные определёнными отправителями. В случае django.db.models.signals.pre_save отправитель будет сохраняемой моделью некоторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel


@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

Функция my_handler будет вызвана только при сохранении объекта класса MyModel.

Отправителями различных сигналов могут быть различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к документации по встроенным сигналам.

Предотвращение дублирования сигналов

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

Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдёт любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

Создание и посылка сигналов.

Вы можете создавать свои собственные сигналы в ваших приложениях.

Создание сигналов

class Signal(providing_args=list)

Все сигналы являются экземплярами класса django.dispatch.Signal, где providing_args – список названий аргументов сигнала, которые будут доступны слушателям. Этот аргумент предназначен просто для документирования, никакой проверки, передаёт ли сигнал эти параметры, не выполняется.

Например:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

Это объявление сигнала pizza_done, который предоставит получателям аргументы toppings и size.

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

Отправка сигналов

В Django существует два способа отправки сигналов.

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

Для отправки сигнала необходимо вызвать Signal.send() или Signal.send_robust(). Вы обязательно должны указать аргумент «sender«(обычно это класс), кроме того можно указать сколько угодно других именованных аргументов.

Например, вот как может выглядеть отправка сигнала pizza_done:

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
        ...

И send(), и send_robust() возвращают список кортежей пар [(receiver, response), ... ]. Каждый кортеж содержит вызываемую функцию и ее ответ.

send() отличается от send_robust() способом обработки исключений, генерируемых функцией-получателем. send() не ловит никаких исключений, сгенерированных в получателе, позволяя исключению проваливаться дальше. Таким образом, не все получатели могут получить сигнал при возникновении ошибки.

send_robust() перехватывает все ошибки, наследуемые от класса Exception языка Python, и гарантирует, что сигнал дойдёт до всех получателей. Если произойдёт ошибка в одном из них, экземпляр исключения будет помещён в кортежную пару, для получателя, который соответствует вызываемой ошибке.

Добавлено в Django 1.8:

Трассировочная информация доступна через атрибут __traceback__ ошибок, возвращаемых при вызове send_robust().

Отключение сигнала

Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)

Чтобы отключить получатель от сигнала, вызовите Signal.disconnect(). Аргументы те же, что и у Signal.connect(). Метод возвращает True в случае, если получатель был отключен и False — если нет.

В аргументе receiver указывается получатель, который должен перестать получать сигнал. Аргумент может содержать None, если для идентификации получателя используется dispatch_uid.

Изменено в Django 1.8:

Было добавлено возвращение булева значения.

Не рекомендуется, начиная с версии 1.9: Аргумент weak устарел и не имеет никакого эффекта. Он будет удален в Django 2.0.

Сигналы — Документация Django 1.7

Django содержит “диспетчер сигналов”, который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определённым отправителям уведомлять некоторый набор получателей о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.

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

Вы можете также определять и посылать свои собственные сигналы; см. ниже.

Прослушивание сигналов

Для того, чтобы принять сигнал, Вам необходимо с помощью метода Signal.connect() зарегистрировать функцию receiver, которая вызывается, когда сигнал послан:

Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None])
Параметры:
  • receiver – Функция, которая будет привязана к этому сигналу. Смотрите Функции-получатели.
  • sender – Указывает конкретного отправителя. Смотрите Сигналы, получаемые от определённых отправителей..
  • weak – Django сохраняет обработчики сигналов используя слабые ссылки(weak references). По этому, если функция-обработчик является локальной функцией, сборщик мусора может удалить ее. Чтобы избежать этого, передайте weak=False в connect().
  • dispatch_uid – Уникальный идентификатор получателя сигнала. На случай, если назначение обработчика может вызываться несколько раз. Смотрите Предотвращение дублирования сигналов.

Давайте посмотрим, как это работает, зарегистрировав сигнал request_finished, который вызывается после завершения выполнения HTTP запроса.

Функции-получатели

Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом следующего вида:

def my_callback(sender, **kwargs):
    print("Request finished!")

Заметьте, что функция принимает аргумент sender, а также аргументы (**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.

Отправителей мы рассмотрим чуть позже, а сейчас обратите внимание на аргументы **kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде my_callback(sender).

Это было бы неверно – на самом деле, Django выдаст ошибку, если Вы это сделаете. Так произойдёт, потому что при любом вызове аргументы могут быть добавлены к сигналу и получатель должен быть в состоянии обработать эти новые аргументы.

Регистрация функции-получателя

Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:

from django.core.signals import request_finished

request_finished.connect(my_callback)

Кроме того, вы можете использовать декоратор receiver() при определении вашего получателя:

receiver(signal)
Параметры:signal – Сигнал или список обрабатываемых сигналов.

Вот как можно использовать декоратор:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

Теперь наша функция my_callback будет вызываться каждый раз, когда запрос завершается.

Куда положить этот код?

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

На практике, обработчики сигналов лежат в модуле signals приложения, к которому они относятся. Подключение к сигналам выполняется в методе ready() конфигурационного класса приложения. При использовании декоратора receiver() просто импортируйте модуль signals в ready().

Изменено в Django 1.7:

Т.к. ready() не существует в предыдущих версиях Django, регистрацию обработчиков сигналов обычно выполняют в модуле models.

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

Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определённое подмножество этих сигналов. Например, рассмотрим django.db.models.signals.pre_save — сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:

В этих случаях Вы можете получать только сигналы, посланные определёнными отправителями. В случае django.db.models.signals.pre_save отправитель будет сохраняемой моделью некоторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel

@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

Функция my_handler будет вызвана только при сохранении объекта класса MyModel.

Отправителями различных сигналов могут быть различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к документации по встроенным сигналам.

Предотвращение дублирования сигналов

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

Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдёт любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

Создание и посылка сигналов.

Вы можете создавать свои собственные сигналы в ваших приложениях.

Создание сигналов

class Signal([providing_args=list])

Все сигналы являются экземплярами класса django.dispatch.Signal, где providing_args – список названий аргументов сигнала, которые будут доступны слушателям. Этот аргумент предназначен просто для документирования, никакой проверки, передаёт ли сигнал эти параметры, не выполняется.

Например:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

Это объявление сигнала pizza_done, который предоставит получателям аргументы toppings и size.

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

Отправка сигналов

В Django существует два способа отправки сигналов.

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

Для отправки сигнала необходимо вызвать Signal.send() или Signal.send_robust(). Вы обязательно должны указать аргумент «sender«(обычно это класс), кроме того можно указать сколько угодно других именованных аргументов.

Например, вот как может выглядеть отправка сигнала pizza_done.

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
        ...

И send(), и send_robust() возвращают список кортежей пар [(receiver, response), … ]. Каждый кортеж содержит вызываемую функцию и ее ответ.

send() отличается от send_robust() способом обработки исключений, генерируемых функцией-получателем. send() не ловит никаких исключений, сгенерированных в получателе, позволяя исключению проваливаться дальше. Таким образом, не все получатели могут получить сигнал при возникновении ошибки.

send_robust() перехватывает все ошибки, наследуемые от класса Exception языка Python, и гарантирует, что сигнал дойдёт до всех получателей. Если произойдёт ошибка в одном из них, экземпляр исключения будет помещён в кортежную пару, для получателя, который соответствует вызываемой ошибке.

Отключение сигнала

Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])

Чтобы отключить получатель от сигнала, вызовите Signal.disconnect(). Аргументы те же, что и у Signal.connect().

В аргументе receiver указывается получатель, который должен перестать получать сигнал. receiver может быть None, если для идентификации получателя используется dispatch_uid.

Сигналы — Документация Django 1.8

Django содержит “диспетчер сигналов”, который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определённым отправителям уведомлять некоторый набор получателей о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.

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

Вы можете также определять и посылать свои собственные сигналы; см. ниже.

Прослушивание сигналов

Для того, чтобы принять сигнал, Вам необходимо с помощью метода Signal.connect() зарегистрировать функцию receiver, которая вызывается, когда сигнал послан:

Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None])
Параметры:
  • receiver – Функция, которая будет привязана к этому сигналу. Смотрите Функции-получатели.
  • sender – Указывает конкретного отправителя. Смотрите Сигналы, получаемые от определённых отправителей..
  • weak – Django сохраняет обработчики сигналов используя слабые ссылки(weak references). Поэтому, если функция-обработчик является локальной функцией, сборщик мусора может удалить ее. Чтобы избежать этого, передайте weak=False в connect().
  • dispatch_uid – Уникальный идентификатор получателя сигнала. На случай, если назначение обработчика может вызываться несколько раз. Смотрите Предотвращение дублирования сигналов.

Давайте посмотрим, как это работает, зарегистрировав сигнал request_finished, который вызывается после завершения выполнения HTTP запроса.

Функции-получатели

Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом:

def my_callback(sender, **kwargs):
    print("Request finished!")

Заметьте, что функция принимает аргумент sender, а также аргументы (**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.

Отправителей мы рассмотрим чуть позже, а сейчас обратите внимание на аргументы **kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде my_callback(sender).

Это было бы неверно – на самом деле, Django выдаст ошибку, если Вы это сделаете. Так произойдёт, потому что при любом вызове аргументы могут быть добавлены к сигналу и получатель должен быть в состоянии обработать эти новые аргументы.

Регистрация функции-получателя

Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:

from django.core.signals import request_finished

request_finished.connect(my_callback)

Кроме того, вы можете использовать декоратор receiver() при определении вашего получателя:

receiver(signal)
Параметры:signal – Сигнал или список обрабатываемых сигналов.

Вот как можно использовать декоратор:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

Теперь наша функция my_callback будет вызываться каждый раз, когда запрос завершается.

Куда положить этот код?

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

На практике, обработчики сигналов лежат в модуле signals приложения, к которому они относятся. Подключение к сигналам выполняется в методе ready() конфигурационного класса приложения. При использовании декоратора receiver() просто импортируйте модуль signals в ready().

Изменено в Django 1.7:

Т.к. ready() не существует в предыдущих версиях Django, регистрацию обработчиков сигналов обычно выполняют в модуле models.

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

Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определённое подмножество этих сигналов. Например, рассмотрим django.db.models.signals.pre_save — сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:

В этих случаях Вы можете получать только сигналы, посланные определёнными отправителями. В случае django.db.models.signals.pre_save отправитель будет сохраняемой моделью некоторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel


@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

Функция my_handler будет вызвана только при сохранении объекта класса MyModel.

Отправителями различных сигналов могут быть различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к документации по встроенным сигналам.

Предотвращение дублирования сигналов

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

Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдёт любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

Создание и посылка сигналов.

Вы можете создавать свои собственные сигналы в ваших приложениях.

Создание сигналов

class Signal([providing_args=list])

Все сигналы являются экземплярами класса django.dispatch.Signal, где providing_args – список названий аргументов сигнала, которые будут доступны слушателям. Этот аргумент предназначен просто для документирования, никакой проверки, передаёт ли сигнал эти параметры, не выполняется.

Например:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

Это объявление сигнала pizza_done, который предоставит получателям аргументы toppings и size.

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

Отправка сигналов

В Django существует два способа отправки сигналов.

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

Для отправки сигнала необходимо вызвать Signal.send() или Signal.send_robust(). Вы обязательно должны указать аргумент «sender«(обычно это класс), кроме того можно указать сколько угодно других именованных аргументов.

Например, вот как может выглядеть отправка сигнала pizza_done:

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
        ...

И send(), и send_robust() возвращают список кортежей пар [(receiver, response), … ]. Каждый кортеж содержит вызываемую функцию и ее ответ.

send() отличается от send_robust() способом обработки исключений, генерируемых функцией-получателем. send() не ловит никаких исключений, сгенерированных в получателе, позволяя исключению проваливаться дальше. Таким образом, не все получатели могут получить сигнал при возникновении ошибки.

send_robust() перехватывает все ошибки, наследуемые от класса Exception языка Python, и гарантирует, что сигнал дойдёт до всех получателей. Если произойдёт ошибка в одном из них, экземпляр исключения будет помещён в кортежную пару, для получателя, который соответствует вызываемой ошибке.

Добавлено в Django 1.8:

Трассировочная информация доступна через атрибут __traceback__ ошибок, возвращаемых при вызове send_robust().

Отключение сигнала

Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])

Чтобы отключить получатель от сигнала, вызовите Signal.disconnect(). Аргументы те же, что и у Signal.connect(). Метод возвращает True в случае, если получатель был отключен и False — если нет.

В аргументе receiver указывается получатель, который должен перестать получать сигнал. Аргумент может содержать None, если для идентификации получателя используется dispatch_uid.

Изменено в Django 1.8:

Было добавлено возвращение булева значения.

Сигналы — Документация Django 3.0

Django содержит «диспетчер сигналов», который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определённым отправителям уведомлять некоторый набор получателей о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.

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

Вы можете также определять и посылать свои собственные сигналы; см. ниже.

Прослушивание сигналов

To receive a signal, register a receiver function using the
Signal.connect() method. The receiver function is called when the signal
is sent. All of the signal’s receiver functions are called one at a time, in
the order they were registered.

Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)
Параметры:
  • receiver – Функция, которая будет привязана к этому сигналу. Смотрите Функции-получатели.
  • sender – Указывает конкретного отправителя. Смотрите Сигналы, получаемые от определённых отправителей..
  • weak – Django сохраняет обработчики сигналов используя слабые ссылки(weak references). Поэтому, если функция-обработчик является локальной функцией, сборщик мусора может удалить ее. Чтобы избежать этого, передайте weak=False в connect().
  • dispatch_uid – Уникальный идентификатор получателя сигнала. На случай, если назначение обработчика может вызываться несколько раз. Смотрите Предотвращение дублирования сигналов.

Давайте посмотрим, как это работает, зарегистрировав сигнал request_finished, который вызывается после завершения выполнения HTTP запроса.

Функции-получатели

Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом:

def my_callback(sender, **kwargs):
    print("Request finished!")

Заметьте, что функция принимает аргумент sender, а также аргументы (**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.

Отправителей мы рассмотрим чуть позже, а сейчас обратите внимание на аргументы **kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде my_callback(sender).

Это было бы неверно – на самом деле, Django выдаст ошибку, если Вы это сделаете. Так произойдёт, потому что при любом вызове аргументы могут быть добавлены к сигналу и получатель должен быть в состоянии обработать эти новые аргументы.

Регистрация функции-получателя

Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:

from django.core.signals import request_finished

request_finished.connect(my_callback)

Кроме того, вы можете использовать декоратор receiver() при определении вашего получателя:

receiver(signal)
Параметры:signal – Сигнал или список обрабатываемых сигналов.

Вот как можно использовать декоратор:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

Теперь наша функция my_callback будет вызываться каждый раз, когда запрос завершается.

Куда положить этот код?

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

In practice, signal handlers are usually defined in a signals
submodule of the application they relate to. Signal receivers are
connected in the ready() method of your
application configuration class. If you’re using the receiver()
decorator, import the signals submodule inside
ready().

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

Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определённое подмножество этих сигналов. Например, рассмотрим django.db.models.signals.pre_save — сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:

В этих случаях Вы можете получать только сигналы, посланные определёнными отправителями. В случае django.db.models.signals.pre_save отправитель будет сохраняемой моделью некоторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel


@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

Функция my_handler будет вызвана только при сохранении объекта класса MyModel.

Отправителями различных сигналов могут быть различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к документации по встроенным сигналам.

Предотвращение дублирования сигналов

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

Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдёт любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

Создание и посылка сигналов.

Вы можете создавать свои собственные сигналы в ваших приложениях.

When to use custom signals

Signals are implicit function calls which make debugging harder. If the
sender and receiver of your custom signal are both within your project,
you’re better off using an explicit function call.

Создание сигналов

class Signal(providing_args=list)

Все сигналы являются экземплярами класса django.dispatch.Signal, где providing_args – список названий аргументов сигнала, которые будут доступны слушателям. Этот аргумент предназначен просто для документирования, никакой проверки, передаёт ли сигнал эти параметры, не выполняется.

Например:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

Это объявление сигнала pizza_done, который предоставит получателям аргументы toppings и size.

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

Отправка сигналов

В Django существует два способа отправки сигналов.

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

Для отправки сигнала необходимо вызвать Signal.send() (все встроенные методы используют его) или Signal.send_robust(). Вы обязательно должны указать аргумент «sender«(обычно это класс), кроме того можно указать сколько угодно других именованных аргументов.

Например, вот как может выглядеть отправка сигнала pizza_done:

class PizzaStore:
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
        ...

И send(), и send_robust() возвращают список кортежей пар [(receiver, response), ... ]. Каждый кортеж содержит вызываемую функцию и ее ответ.

send() отличается от send_robust() способом обработки исключений, генерируемых функцией-получателем. send() не ловит никаких исключений, сгенерированных в получателе, позволяя исключению проваливаться дальше. Таким образом, не все получатели могут получить сигнал при возникновении ошибки.

send_robust() перехватывает все ошибки, наследуемые от класса Exception языка Python, и гарантирует, что сигнал дойдёт до всех получателей. Если произойдёт ошибка в одном из них, экземпляр исключения будет помещён в кортежную пару, для получателя, который соответствует вызываемой ошибке.

Трассировочная информация доступна через атрибут __traceback__ ошибок, возвращаемых при вызове send_robust().

Отключение сигнала

Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)

Чтобы отключить получатель от сигнала, вызовите Signal.disconnect(). Аргументы те же, что и у Signal.connect(). Метод возвращает True в случае, если получатель был отключен и False — если нет.

В аргументе receiver указывается получатель, который должен перестать получать сигнал. Аргумент может содержать None, если для идентификации получателя используется dispatch_uid.

Сигналы — Документация Django 1.4

Django содержит “диспетчер сигналов”, который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определенным отправителям уведомлять некоторый набор получателей о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.

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

Вы можете также определять и посылать свои собственные сигналы; см. ниже.

Прослушивание сигналов

Для того, чтобы принять сигнал, Вам необходимо с помощью метода Signal.connect() зарегистрировать функцию receiver, которая вызывается, когда сигнал послан:

Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None])

Давайте посмотрим, как это работает, зарегистрировав сигнал request_finished, который вызывается после завершения выполнения HTTP запроса.

Функции-получатели

Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом следующего вида:

def my_callback(sender, **kwargs):
    print "Request finished!"

Заметьте, что функция принимает аргумент sender, а также аргументы (**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.

Отправителей мы рассмотрим чуть позже, а сейчас обратите внимание на аргументы **kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде my_callback(sender).

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

Регистрация функции-получателя

Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:

from django.core.signals import request_finished

request_finished.connect(my_callback)

Кроме того, вы можете использовать декоратор receiver при определении вашего получателя:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print "Request finished!"

Теперь наша функция my_callback будет вызываться каждый раз, когда запрос завершается.

Добавлено в Django 1.3.

Декоратор receiver был добавлен в Django 1.3.

Where should this code live?

Вы можете расположить обработчик сигнала и регистрировать его там, где Вам удобно. Тем не менее, вы должны убедиться, что регистрация обработчика сигнала происходит до того, как он будет отправлен. Поэтому файл models.py вашего приложения хорошо подходит для регистрации обработчиков сигналов.

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

Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определенное подмножество этих сигналов. Например, рассмотрим django.db.models.signals.pre_save — сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:

В этих случаях Вы можете получать только сигналы, посыланные определенными отправителями. В случае django.db.models.signals.pre_save отправитель будет сохраняемой моделью некторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel

@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

Функция my_handler будет вызвана только при сохранении объекта класса MyModel.

Отправителями различных сигналов могут быть различные различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к документации по встроенным сигналам.

Предотвращение дублирования сигналов

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

Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдет любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

Создание и посылка сигналов.

Вы может создавать свои собственные сигналы в Ваших приложениях.

Создание сигналов

class Signal([providing_args=list])

Все сигналы являются экземплярами класса django.dispatch.Signal, где providing_args — список названий аргументов сигнала, которые будут доступны слушателям.

Например:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

Это объявление сигнала pizza_done, который предоставит получателям аргументы toppings и size.

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

Отправка сигналов

В Django существует два способа отправки сигналов.

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

Для отправки сигнала необходимо вызвать Signal.send() или Signal.send_robust(). Вы обязательно должны указать аргумент sender, кроме того можно указать сколько угодно других именованных аргументов.

Например, вот как может выглядать отправка сигнала pizza_done.

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self, toppings=toppings, size=size)
        ...

И 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.

Django — сигналы | django Tutorial

Теперь детали.

Сигналы Django — это способ информировать ваше приложение о некоторых задачах (например, о модели до или после сохранения или удаления), когда это происходит.

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

Например, в любое время , когда создается новый пользователь Django, Пользовательская модель выпускает сигнал с ассоциированными параметрами, такими как sender=User что позволяет вам конкретно настроить ваше прослушивание сигналов на конкретную деятельность, которая происходит, в этом случае новое создание пользователя ,

В приведенном выше примере намерение состоит в создании объекта UserProfile сразу после создания объекта User. Поэтому, прослушивая сигнал post_save из модели User (по умолчанию Django User Model), мы создаем объект UserProfile сразу после создания нового User .

Документация Django предоставляет обширную документацию по всем возможным сигналам .

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

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

Сигналы отлично подходят, как обычно, не для всех. Вход / Выход, сигналы отличные. Ключевые модели, выпускающие знаки, такие как User Model, если они прекрасны.

Создание сигналов для каждой модели в вашем приложении может быть подавляющим в какой-то момент и победить всю идею спаррингового использования сигналов Django.

Не используйте сигналы, когда (на основе Two Scoops of Django book ):

  • Сигнал относится к одной конкретной модели и может быть перенесен в один из методов этой модели, возможно, вызванный функцией save() .
  • Сигнал можно заменить специальным методом диспетчера модели.
  • Сигнал относится к определенному виду и может быть перемещен в эту точку зрения

Можно использовать сигналы, когда:

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

Сигналы — Документация Django 1.5.2

Django содержит “диспетчер сигналов”, который позволяет одним приложениям фреймворка получать уведомления от других после того, как в последних произойдут некоторые события. Вкратце, сигналы позволяют определённым отправителям уведомлять некоторый набор получателей о совершении действий. Сигналы особенно полезны, когда поведение многих фрагментов кода зависит от инициации одних и тех же событий.

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

Вы можете также определять и посылать свои собственные сигналы; см. ниже.

Прослушивание сигналов

Для того, чтобы принять сигнал, Вам необходимо с помощью метода Signal.connect() зарегистрировать функцию receiver, которая вызывается, когда сигнал послан:

Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None])

Давайте посмотрим, как это работает, зарегистрировав сигнал request_finished, который вызывается после завершения выполнения HTTP запроса.

Функции-получатели

Во-первых, мы должны определить функцию-получатель. Получатель должен быть Python функцией или методом следующего вида:

def my_callback(sender, **kwargs):
    print("Request finished!")

Заметьте, что функция принимает аргумент sender, а также аргументы (**kwargs) в формате словаря; все обработчики сигналов должны принимать подобные аргументы.

Отправителей мы рассмотрим чуть позже, а сейчас обратите внимание на аргументы **kwargs. Все сигналы имеют возможность посылать именованные аргументы и могут изменить их набор в любой момент. Сигнал request_finished документирован как не посылающий аргументов, и у нас может появиться искушение записывать наш обработчик сигнала в виде my_callback(sender).

Это было бы неверно – на самом деле, Django выдаст ошибку, если Вы это сделаете. Так произойдёт, потому что при любом вызове аргументы могут быть добавлены к сигналу и получатель должен быть в состоянии обработать эти новые аргументы.

Регистрация функции-получателя

Есть два способа, которыми Вы можете подключить получатель к сигналу. Вы можете вручную вызвать connect:

from django.core.signals import request_finished

request_finished.connect(my_callback)

Кроме того, вы можете использовать декоратор receiver при определении вашего получателя:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

Теперь наша функция my_callback будет вызываться каждый раз, когда запрос завершается.

receiver может также принимать список сигналов.

Изменено в Django 1.5.

Была добавлена возможность передать список сигналов.

Where should this code live?

Вы можете расположить обработчик сигнала и зарегистрировать его там, где Вам удобно. Тем не менее, вы должны убедиться, что регистрация обработчика сигнала происходит до того, как он будет отправлен. Поэтому файл models.py вашего приложения хорошо подходит для регистрации обработчиков сигналов.

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

Некоторые сигналы могу быть посланы много раз, но Вам будет нужно получать только определённое подмножество этих сигналов. Например, рассмотрим django.db.models.signals.pre_save — сигнал, посылаемый перед сохранением модели. Бывает, что Вам не нужно знать о сохранении любой модели, Вас интересует только одна конкретная модель:

В этих случаях Вы можете получать только сигналы, посланные определёнными отправителями. В случае django.db.models.signals.pre_save отправитель будет сохраняемой моделью некоторого класса, так что вы можете указать, что вы хотите получать только сигналы, посылаемые этой моделью:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel

@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

Функция my_handler будет вызвана только при сохранении объекта класса MyModel.

Отправителями различных сигналов могут быть различные объекты. Для получения детальной информации по каждому такому сигналу обращайтесь к документации по встроенным сигналам.

Предотвращение дублирования сигналов

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

Такое поведение может приводить к проблемам (например, если происходит отправка электронной почты всякий раз, когда посылается сигнал о сохранении модели), поэтому передавайте некоторый уникальный идентификатор в качестве значения аргумента dispatch_uid для идентификации в функции-получателе. Обычно, этот идентификатор является строкой, хотя подойдёт любой хешируемый объект. В итоге функция-получатель будет привязана к сигналу единожды для каждого уникального значения dispatch_uid.

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

Создание и посылка сигналов.

Вы можете создавать свои собственные сигналы в ваших приложениях.

Создание сигналов

class Signal([providing_args=list])

Все сигналы являются экземплярами класса django.dispatch.Signal, где providing_args – список названий аргументов сигнала, которые будут доступны слушателям. Этот аргумент предназначен просто для документирования, никакой проверки, передаёт ли сигнал эти параметры, не выполняется.

Например:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

Это объявление сигнала pizza_done, который предоставит получателям аргументы toppings и size.

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

Отправка сигналов

В Django существует два способа отправки сигналов.

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

Для отправки сигнала необходимо вызвать Signal.send() или Signal.send_robust(). Вы обязательно должны указать аргумент sender, кроме того можно указать сколько угодно других именованных аргументов.

Например, вот как может выглядать отправка сигнала pizza_done.

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self, toppings=toppings, size=size)
        ...

И send(), и send_robust() возвращают список кортежей пар [(receiver, response), … ]. Каждый кортеж содержит вызываемую функцию и ее ответ.

send() отличается от send_robust() способом обработки исключений, генерируемых функцией-получателем. send() не ловит никаких исключений, сгенерированных в получателе, позволяя исключению проваливаться дальше. Таким образом, не все получатели могут получить сигнал при возникновении ошибки.

send_robust() перехватывает все ошибки, наследуемые от класса Exception языка Python, и гарантирует, что сигнал дойдёт до всех получателей. Если произойдёт ошибка в одном из них, экземпляр исключения будет помещён в кортежную пару, для получателя, который соответствует вызываемой ошибке.

Отключение сигнала

Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])

Чтобы отключить получатель от сигнала, вызовите Signal.disconnect(). Аргументы те же, что и у Signal.connect().

В аргументе receiver указывается получатель, который должен перестать получать сигнал. receiver может быть None, если для идентификации получателя используется dispatch_uid.

Как создавать сигналы Django

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

Другой распространенный вариант использования — это расширение настраиваемого пользователя Django с помощью стратегии профиля через
отношения один на один.Обычно мы используем «диспетчер сигналов» для прослушивания события пользователя post_save .
чтобы также обновить экземпляр Profile. Я рассказал об этом случае в другом посте, который вы можете прочитать здесь:
Как расширить модель пользователя Django.

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


Когда мне его использовать?

Прежде чем двигаться дальше, узнайте , когда вам следует его использовать :

  • Когда одни и те же события могут интересовать несколько частей кода;
  • Когда вам нужно взаимодействовать с изолированным приложением, например.г.:
    • Базовая модель Django;
    • Модель, определенная сторонним приложением.

Как это работает?

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

В аппаратуре сигналов есть два ключевых элемента: передатчики и приемники . Как следует из названия,
отправитель является ответственным за отправку сигнала, а получатель — тот, кто получит этот сигнал и
тогда сделай что-нибудь.

Приемник должен быть функцией или методом экземпляра, который должен принимать сигналы.

Отправитель должен быть либо объектом Python, либо None, чтобы получать события от любого отправителя.

Соединение между отправителями и приемниками осуществляется через «диспетчеров сигналов», которые являются экземплярами
Сигнал , через метод connect .

Ядро Django также определяет ModelSignal , который является подклассом Signal , который позволяет отправителю быть ленивым.
указана как строка app_label.Форма ModelName . Но, вообще говоря, вы всегда будете использовать
Signal — класс для создания собственных сигналов.

Итак, чтобы получить сигнал, вам необходимо зарегистрировать функцию приемника , которая вызывается, когда сигнал отправляется с помощью
метод Signal.connect () .


Использование

Давайте посмотрим на встроенный сигнал post_save . Его код находится в модуле django.db.models.signals . Эта
конкретный сигнал срабатывает сразу после того, как модель завершит выполнение метода save .

  от пользователя django.contrib.auth.models import
из django.db.models.signals import post_save

def save_profile (отправитель, экземпляр, ** kwargs):
    instance.profile.save ()

post_save.connect (save_profile, sender = User)  

В приведенном выше примере save_profile — это наша функция получателя , Пользователь — это отправитель и post_save — это
сигнал . Вы можете читать это так: Каждый раз, когда экземпляр User завершает выполнение своего метода save ,
save_profile функция будет выполнена.

Если вы подавите аргумент отправителя следующим образом: post_save.connect (save_profile) , функция save_profile будет
выполняться после того, как любая модель Django выполнит метод save .

Другой способ зарегистрировать сигнал — использовать декоратор @receiver :

 Приемник  def (сигнал, ** kwargs)  

Параметр signal может быть либо экземпляром Signal , либо списком / кортежем из экземпляров Signal .

См. Пример ниже:

  от пользователя django.contrib.auth.models import
из django.db.models.signals import post_save
из приемника импорта django.dispatch

@receiver (post_save, sender = Пользователь)
def save_profile (отправитель, экземпляр, ** kwargs):
    instance.profile.save ()  

Если вы хотите зарегистрировать функцию приемника для нескольких сигналов, вы можете сделать это следующим образом:

  @receiver ([post_save, post_delete], sender = User)  

Где должен находиться код?

В зависимости от того, где вы регистрируете сигналы своего приложения, могут возникнуть некоторые побочные эффекты из-за импорта
код.Поэтому рекомендуется не помещать его в модуль моделей или в корневой модуль приложения.

Документация Django советует поместить сигналы в файл конфигурации вашего приложения. См. Ниже, что я обычно делаю,
учитывая приложение Django с именем Profile :

профилей / signal.py:

  от пользователя django.contrib.auth.models import
из django.db.models.signals import post_save
из приемника импорта django.dispatch

из cmdbox.Profile.models импорт профиля

@receiver (post_save, sender = Пользователь)
def create_user_profile (отправитель, экземпляр, создано, ** kwargs):
    если создано:
        Profile.objects.create (пользователь = экземпляр)

@receiver (post_save, sender = Пользователь)
def save_user_profile (отправитель, экземпляр, ** kwargs):
    instance.profile.save ()  

профилей / app.py:

  из django.apps import AppConfig
из django.utils.translation импортируйте ugettext_lazy как _

класс ProfilesConfig (AppConfig):
    name = 'cmdbox.профили
    verbose_name = _ ('профили')

    def готов (сам):
        импорт cmdbox.profiles.signals # noqa  

профилей / __ init__.py:

  default_app_config = 'cmdbox.profiles.apps.ProfilesConfig'  

В приведенном выше примере простой импорт модуля сигналов внутри метода ready () будет работать, потому что я использую
декоратор @receiver () . Если вы подключаете функцию приемника с помощью метода connect () , см.
пример ниже:

профилей / сигналов.py:

  из профиля импорта cmdbox.profiles.models

def create_user_profile (отправитель, экземпляр, создано, ** kwargs):
    если создано:
        Profile.objects.create (пользователь = экземпляр)

def save_user_profile (отправитель, экземпляр, ** kwargs):
    instance.profile.save ()  

профилей / app.py:

  из django.apps import AppConfig
из django.contrib.auth.models импортировать пользователя
из django.db.models.signals import post_save
из django.utils.translation импортируйте ugettext_lazy как _

из cmdbox.profile.signals import create_user_profile, save_user_profile

класс ProfilesConfig (AppConfig):
    имя = 'cmdbox.profiles'
    verbose_name = _ ('профили')

    def готов (сам):
        post_save.connect (create_user_profile, sender = Пользователь)
        post_save.connect (save_user_profile, sender = User)  

профилей / __ init__.py:

  default_app_config = 'cmdbox.profiles.apps.ProfilesConfig'  

Примечание. Профили / __ init__.py бит не требуются, если вы уже ссылаетесь на свой AppConfig в
INSTALLED_APPS настройки.


Встроенные сигналы Django

Здесь вы можете найти список некоторых полезных встроенных сигналов. Он не полный, но это самые распространенные.

Модель сигналов

django.db.models.signals. pre_init :

  функция-получателя (отправитель, * аргументы, ** kwargs)  

django.db.models.signals. post_init :

  функция-получатель (отправитель, экземпляр)  

django.db.models.signals. pre_save :

  функция-получатель (отправитель, экземпляр, необработанный, использование, поля_обновления)  

django.db.models.signals. post_save :

  функция-получатель (отправитель, экземпляр, созданный, необработанный, использующий, update_fields)  

django.db.models.signals. pre_delete :

  функция-получатель (отправитель, экземпляр, использующий)  

django.db.models.signals. post_delete :

  Receiver_function (отправитель, экземпляр, использование)  

django.db.models.signals. м2 м_изменилось :

  функция-получателя (отправитель, экземпляр, действие, реверс, модель, pk_set, использование)  
Сигналы запроса / ответа

django.core.signals. request_started :

  функция-получатель (отправитель, среда)  

django.core.signals. request_finished :

  функция-получатель (отправитель, среда)  

django.core.signals. got_request_exception :

  Receiver_function (sender, request)  

Если вы хотите увидеть весь список, щелкните здесь, чтобы получить доступ к официальной документации.

.

сигналов | Документация Django 3.1

Список всех сигналов, которые отправляет Django. Все встроенные сигналы отправляются
используя метод send () .

Сигналы модели¶

Модуль django.db.models.signals определяет набор сигналов, отправляемых
модельная система.

Предупреждение

Многие из этих сигналов отправляются различными модельными методами, например
__init __ () или save () , что можно
переопределить в вашем собственном коде.

Если вы переопределите эти методы в своей модели, вы должны вызвать родительский класс ’
методы отправки этих сигналов.

Обратите внимание, что Django по умолчанию хранит обработчики сигналов как слабые ссылки,
поэтому, если ваш обработчик является локальной функцией, он может быть собран сборщиком мусора. Чтобы
чтобы предотвратить это, передайте weak = False , когда вы вызываете connect () сигнала.

Примечание

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

pre_init

django.db.models.signals. pre_init

Каждый раз, когда вы создаете экземпляр модели Django, этот сигнал отправляется в начале
метода __init __ () модели.

Аргументы, отправленные с этим сигналом:

отправитель
Класс модели, для которого только что был создан экземпляр.
args
Список позиционных аргументов, переданных в __init __ () .
kwargs
Словарь аргументов ключевых слов, переданных в __init __ () .

Например, в руководстве есть такая строка:

 q = Вопрос (question_text = "Что нового?", Pub_date = timezone.сейчас())
 

Аргументы, отправленные обработчику pre_init , будут:

Аргумент Значение
отправитель Вопрос (сам класс)
аргументы [] (пустой список, потому что не было позиционных
аргументы, переданные в __init __ () )
кваргс {'question_text': «Что нового?»,
'pub_date': дата и время.datetime (2012, 2, 26, 13, 0, 0, 775217, tzinfo = )}

post_init

django.db.models.signals. post_init

Как pre_init, но этот отправляется, когда метод __init __ () завершается.

Аргументы, отправленные с этим сигналом:

отправитель
Как указано выше: класс модели, для которого только что был создан экземпляр.
instance

Фактический экземпляр модели, которая только что была создана.

Примечание

instance._state не устанавливается перед отправкой сигнала post_init ,
поэтому атрибуты _state всегда имеют значения по умолчанию. Например,
_state.db равно Нет и не может использоваться для проверки экземпляра
база данных.

Предупреждение

По соображениям производительности не следует выполнять запросы к получателям
pre_init или post_init сигналов, потому что они будут выполняться для
каждый экземпляр, возвращенный во время итерации набора запросов.

предварительное сохранение

django.db.models.signals. предварительное сохранение

Отправляется в начале модели save ()
метод.

Аргументы, отправленные с этим сигналом:

отправитель
Класс модели.
экземпляр
Текущий сохраняемый экземпляр.
raw
Логическое значение; Истинно , если модель сохранена точно так, как представлено
(я.е. при загрузке приспособления). Не следует запрашивать / изменять другие
записей в базе данных, поскольку база данных может не находиться в
согласованного состояния пока нет.
с использованием
Используемый псевдоним базы данных.
update_fields
Набор полей для обновления, переданных в Model.save () или Нет
если update_fields не было передано в save () .

post_save

джанго.db.models.signals. post_save

Как pre_save , но отправляется в конце
save () метод.

Аргументы, отправленные с этим сигналом:

отправитель
Класс модели.
экземпляр
Текущий сохраняемый экземпляр.
создано
Логическое значение; Истинно , если была создана новая запись.
raw
Логическое значение; Истинно , если модель сохранена точно так, как представлено
(я.е. при загрузке приспособления). Не следует запрашивать / изменять другие
записей в базе данных, поскольку база данных может не находиться в
согласованного состояния пока нет.
с использованием
Используемый псевдоним базы данных.
update_fields
Набор полей для обновления, переданных в Model.save () или Нет
если update_fields не было передано в save () .

pre_delete

джанго.db.models.signals. pre_delete

Отправляется в начале модели delete ()
метод и метод delete () набора запросов.

Аргументы, отправленные с этим сигналом:

отправитель
Класс модели.
экземпляр
Фактический удаляемый экземпляр.
с использованием
Используемый псевдоним базы данных.

post_delete

джанго.db.models.signals. post_delete

Как pre_delete , но отправляется в конце модели
delete () метод и набор запросов
delete () метод.

Аргументы, отправленные с этим сигналом:

отправитель
Класс модели.
экземпляр

Фактический удаляемый экземпляр.

Обратите внимание, что объекта больше не будет в базе данных, так что
осторожно, что вы делаете с этим экземпляром.

с использованием
Используемый псевдоним базы данных.

м2 м_изменилось

django.db.models.signals. м2 м_изменилось

Отправляется, когда ManyToManyField изменяется в модели
пример. Строго говоря, это не модельный сигнал, так как его посылает
ManyToManyField , но поскольку он дополняет
pre_save / post_save и pre_delete / post_delete
когда дело доходит до отслеживания изменений в моделях, это включено сюда.

Аргументы, отправленные с этим сигналом:

отправитель
Промежуточный класс модели, описывающий
ManyToManyField . Этот класс автоматически
создается, когда определено поле «многие ко многим»; вы можете получить к нему доступ, используя
Атрибуты с по в поле "многие ко многим".
экземпляр
Экземпляр, отношение «многие ко многим» обновлено. Это может быть
экземпляр отправителя или класса
ManyToManyField относится к.
действие

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

"pre_add"
Отправляется перед добавлением одного или нескольких объектов в отношение.
"post_add"
Отправляется после того, как один или несколько объектов добавлены в отношение.
"pre_remove"
Отправляется перед тем, как удаляет один или несколько объектов из отношения.
"post_remove"
Отправляется после того, как один или несколько объектов удалены из отношения.
"pre_clear"
Отправлено до , связь очищена.
"post_clear"
Отправляется после того, как связь очищена.
обратное
Указывает, какая сторона отношения обновляется (т. Е. Если это
прямое или обратное отношение, которое изменяется).
модель
Класс объектов, которые добавляются, удаляются или очищаются
от отношения.
pk_set

Для действий pre_add и post_add это набор первичных ключей
значения, которые будут или были добавлены к отношению. Это может быть
подмножество значений, представленных для добавления, поскольку вставки должны фильтровать
существующие значения во избежание ошибки базы данных IntegrityError .

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

Для действий pre_clear и post_clear это Нет .

с использованием
Используемый псевдоним базы данных.

Например, если Pizza может иметь несколько объектов Topping , смоделированных
как это:

 класс Топпинг (модели. Модель):
    # ...
    проходить

класс Пицца (models.Model):
    # ...
    toppings = models.ManyToManyField (Топпинг)
 

Если бы мы подключили такой обработчик:

 из django.db.models.импорт сигналов m2m_changed

def toppings_changed (отправитель, ** kwargs):
    # Сделай что-нибудь
    проходить

m2m_changed.connect (toppings_changed, отправитель = Pizza.toppings.through)
 

, а затем сделал что-то вроде этого:

 >>> p = Pizza.objects.create (...)
>>> t = Topping.objects.create (...)
>>> p.toppings.add (t)
 

аргументы, отправленные обработчику m2m_changed ( toppings_changed в
пример выше) будет:

Аргумент Значение
отправитель Пицца.начинки. через (средний класс м2м)
экземпляр p (экземпляр Pizza изменяется)
действие «pre_add» (за которым следует отдельный сигнал с «post_add» )
реверс Ложь ( Пицца содержит
ManyToManyField , поэтому этот вызов
изменяет прямое отношение)
модель Топпинг (класс объектов, добавленных в
Пицца )
упаковка {т.id} (так как только Topping t было добавлено к отношению)
используя "по умолчанию" (поскольку маршрутизатор по умолчанию отправляет сюда записи)

А если бы мы сделали что-то вроде этого:

 >>> t.pizza_set.remove (p)
 

аргументы, отправленные обработчику m2m_changed , будут:

Аргумент Значение
отправитель Пицца.начинки. через (средний класс м2м)
экземпляр т (модифицируется экземпляр Topping )
действие «pre_remove» (за которым следует отдельный сигнал с «post_remove» )
реверс True ( Пицца содержит
ManyToManyField , поэтому этот вызов
изменяет обратное соотношение)
модель Пицца (класс предметов, снятых с
Топпинг )
упаковка {стр.id} (поскольку только Pizza p было удалено из
отношение)
используя "по умолчанию" (поскольку маршрутизатор по умолчанию отправляет сюда записи)

class_prepared

django.db.models.signals. class_prepared

Отправляется всякий раз, когда класс модели «подготовлен», то есть когда модель
были определены и зарегистрированы в модельной системе Django.Django использует это
сигнал внутренне; он обычно не используется в сторонних приложениях.

Поскольку этот сигнал отправляется во время процесса заполнения реестра приложения, и
AppConfig.ready () запускается после приложения
реестр полностью заполнен, приемники не могут быть подключены в этом методе.
Одна из возможностей - вместо этого подключить их AppConfig .__ init __ () , взяв
старайтесь не импортировать модели и не запускать вызовы в реестр приложений.

Аргументы, которые отправляются с этим сигналом:

отправитель
Класс модели, который только что был подготовлен.

Управляющие сигналы¶

Сигналы, отправленные django-admin.

предварительная миграция

django.db.models.signals. предварительная миграция

Отправляется командой migrate перед началом установки
заявление. Он не выдается для приложений, в которых отсутствует модуль models .

Аргументы, отправленные с этим сигналом:

отправитель
Экземпляр AppConfig для приложения, которое собирается
быть перенесенными / синхронизированными.
app_config
То же, что и отправитель .
подробность

Указывает, сколько информации manage.py выводит на экран. Видеть
флаг --verbosity для подробностей.

Функции, которые прослушивают pre_migrate , должны корректировать то, что они
вывод на экран в зависимости от значения этого аргумента.

интерактивный

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

Например, приложение django.contrib.auth предлагает только создать
superuser, когда interactive - это True .

с использованием
Псевдоним базы данных, с которой будет работать команда.
план
План миграции, который будет использоваться для выполнения миграции.Пока
план не является общедоступным API, это позволяет в редких случаях, когда он
необходимо знать план. План - это список из двух кортежей с первым
элемент является экземпляром класса миграции, а второй элемент показывает
если миграция была отменена ( True ) или применена ( False ).
приложений
Экземпляр приложений , содержащих состояние
перед запуском миграции. Его следует использовать вместо глобального
приложений реестр для получения моделей, которые вы
хотите выполнить операции.

post_migrate

django.db.models.signals. post_migrate

Отправляется в конце миграции (даже если миграции не выполняются) и
сбросить команды. Он не выдается для приложений, в которых отсутствует
модели модуль.

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

Аргументы, отправленные с этим сигналом:

отправитель
Экземпляр AppConfig для приложения, которое было
только что установил.
app_config
То же, что и отправитель .
подробность

Указывает, сколько информации manage.py выводит на экран. Видеть
флаг --verbosity для подробностей.

Функции, которые прослушивают post_migrate , должны настроить то, что они
вывод на экран в зависимости от значения этого аргумента.

интерактивный

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

Например, приложение django.contrib.auth предлагает только создать
superuser, когда interactive - это True .

с использованием
Псевдоним базы данных, используемый для синхронизации. По умолчанию по умолчанию
база данных.
план
План миграции, который использовался для выполнения миграции. Пока план
не общедоступный API, это позволяет в редких случаях, когда необходимо
знать план. План - это список из двух кортежей, первым из которых является
экземпляр класса миграции и второй элемент, показывающий,
миграция была отменена ( True ) или применена ( False ).
приложений
Экземпляр приложений , содержащих состояние
проект после выполнения миграции. Его следует использовать вместо глобального
приложений реестр для получения моделей, которые вы
хотите выполнить операции.

Например, вы можете зарегистрировать обратный вызов в
AppConfig вот так:

 из django.apps импортировать AppConfig
из django.db.models.signals импорт post_migrate

def my_callback (отправитель, ** kwargs):
    # Здесь ваша конкретная логика
    проходить

класс MyAppConfig (AppConfig):
    ...

    def готов (сам):
        post_migrate.connect (my_callback, отправитель = сам)
 

Примечание

Если вы предоставляете экземпляр AppConfig в качестве отправителя
аргумент, убедитесь, что сигнал зарегистрирован в
готово () . AppConfig воссоздаются для
тесты, которые запускаются с измененным набором INSTALLED_APPS (например,
при переопределении настроек), и такие сигналы должны быть подключены для каждого
новый экземпляр AppConfig .

Сигналы запроса / ответа¶

Сигналы, отправленные базовой структурой при обработке запроса.

request_started

django.core.signals. начато_запрос

Отправляется, когда Django начинает обработку HTTP-запроса.

Аргументы, отправленные с этим сигналом:

отправитель
Класс обработчика - например, django.core.handlers.wsgi.WsgiHandler - это
обработал запрос.
Environment
Словарь Environment , предоставленный запросу.

request_finished

django.core.signals. запрос_ завершен

Отправляется, когда Django завершает доставку HTTP-ответа клиенту.

Аргументы, отправленные с этим сигналом:

отправитель
Класс обработчика, как указано выше.

got_request_exception

django.core.signals. got_request_exception 50

Этот сигнал отправляется всякий раз, когда Django обнаруживает исключение при обработке входящего HTTP-запроса.

Аргументы, отправленные с этим сигналом:

отправитель
Не используется (всегда Нет ).
запрос
Объект HttpRequest .

Тестовые сигналы

Сигналы отправляются только при выполнении тестов.

настройка_изменена

django.test.signals. настройка_изменена

Этот сигнал отправляется, когда значение параметра изменяется через
django.test.TestCase.settings () контекстный менеджер или
django.test.override_settings () декоратор / менеджер контекста.

На самом деле он отправляется дважды: когда применяется новое значение («настройка») и когда
восстанавливается первоначальная стоимость («разборка»). Используйте аргумент введите , чтобы
различать эти два.

Вы также можете импортировать этот сигнал из django.core.signals , чтобы избежать импорта
из django.test в не тестовых ситуациях.

Аргументы, отправленные с этим сигналом:

отправитель
Обработчик настроек.
настройка
Название настройки.
значение
Значение настройки после изменения. Для настроек, которые изначально
не существует, на этапе «разборки» значение равно Нет .
введите
Логическое значение; Истина , если настройка применяется, Ложь , если восстановлена.

template_rendered

джанго.test.signals. template_rendered

Отправляется, когда тестовая система отображает шаблон. Этот сигнал не издается во время
нормальная работа сервера Django - доступна только во время тестирования.

Аргументы, отправленные с этим сигналом:

отправитель
Объект Template , который был визуализирован.
шаблон
То же, что и отправитель
контекст
Контекст , с которым шаблон был
оказано.

.

Понимание сигналов Django

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

Вот некоторые из наиболее часто используемых сигналов моделей:

  • pre_save / post_save : Этот сигнал генерируется до / после метода save ().

  • pre_delete / post_delete : Перед удалением экземпляра модели (метод delete ()) выдается этот сигнал.

  • pre_init / post_init : Этот сигнал работает до / после создания экземпляра модели (метод __init __ ())

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

Подключение сигналов

Вы можете связать свои функции с сигналами двумя разными способами:

Декоратор : С помощью декоратора @receiver мы можем связать сигнал с функцией:

  из django.db.models.signals import post_save
из приемника импорта django.dispatch
from someapp.models импортировать MyModel

@receiver (post_save, отправитель = MyModel)
def my_function_post_save (отправитель, ** kwargs):
# выполнить действие…  

Каждый раз, когда экземпляр MyModel завершает выполнение своего метода save (), my_function_post_save начинает работать.

Другой способ - соединить сигнал с функцией :

  post_save.connect (my_function_post_save, отправитель = MyModel)  

Как мы можем использовать сигнальную функцию с несколькими отправителями?

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

Подробнее о сигналах django можно узнать в официальной документации.

  @receiver (post_save, sender = MyBaseClassModel .__ подклассы __ ())  
  для подкласса в MyBaseClassModel .__ подклассы __ ():
post_save.connect (my_function_post_save, sender = sub_class) 
 
  1. Мы можем использовать список в качестве аргумента отправителя для @receiver: del.
  2. Другим способом мы можем использовать цикл for:

Куда мне писать свои сигналы?

Начиная с Django 1.7 , официальная документация предлагает нам записать наши функции сигналов в другой файл (например, signal.py) и связать их с сигналами в файле apps.py нашего приложения . Вот пример:

  # signal.py
def my_signal_function (отправитель, ** kwargs):
print ("печать сообщения ...")
  
  # apps.py
из django.apps импортировать AppConfig
из django.db.models.signals import post_save
из django.utils.translation импортирует ugettext_lazy как _
из .signals import my_signal_function


класс MyAPPConfig (AppConfig):
name = 'myapp'
verbose_name = _ ('Мое приложение')

def готов (сам):
myccl = self.get_model ('MyCustomClass')
post_save.connect (my_signal_function, sender = myccl, dispatch_uid = "my_unique_identifier")  

Иногда сигнал вызывается более одного раза. По этой причине мы используем уникальную строку с аргументом dispatch_uid в функции подключения.

Для чего это используется?

Ну, мы уже знаем, как настроить наши сигналы и сигналы , функцию , но когда мы должны его использовать? Здесь мы покажем вам несколько мощных примеров сигналов django :

  • У нас может быть модель, которая хранит файл на диске, то есть DrivingLicenseModel. Эта модель будет иметь 3 атрибута: имя, срок_выпуска и фотография. Фотография будет изображением, которое мы сохраним на диске.
    Мы можем использовать сигнал pre_delete для удаления образа диска перед удалением нашего экземпляра DrivingLicenseModel.

  • У нас есть список фильмов для каждого пользователя на нашем веб-сайте (ListMoviesModel), который имеет атрибут в последний раз, когда пользователь его изменял. Пользователь может добавить фильм (ListMoviesEntryModel) в предыдущий список.
    Каждый раз, когда пользователь добавляет или изменяет отдельный фильм, мы можем обновить атрибут last_modification экземпляра ListMoviesModel для этого пользователя, если мы установим сигнал post_save для модели ListMoviesEntryModel.

Подробнее о сигналах django можно узнать в официальной документации.

.

сигналов Django - чрезвычайно упрощенное объяснение для начинающих. (Пример)

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

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


«Нахрен сигналы, как они работают ?!»

Когда django получает запрос контента по определенному URL-адресу, механизм маршрутизации запросов выбирает соответствующее представление, как определено вашим urls.py , для генерации контента. Для типичного запроса GET это включает извлечение соответствующей информации из базы данных и передачу ее в шаблон, который создает HTML-код для отображения и отправляет его запрашивающему пользователю. Действительно, довольно тривиально.

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

Рассмотрим, например, ситуацию, когда вам нужно создать профиль для каждого нового пользователя, который регистрируется на вашем сайте. По умолчанию Django предоставляет базовую модель User через модуль django.contrib.auth . Любую дополнительную информацию можно добавить либо путем настройки модели User , либо путем создания отдельной модели UserProfile в отдельном приложении.

Хорошо, я выбираю ПОСЛЕДНИЙ вариант.

Хорошо, допустим, наша модель UserProfile выглядит так:

  GENDER_CHOICES = (
('М', 'Мужской'),
('F', 'Женский'),
('P', 'Предпочитаю не отвечать'),
)
класс UserProfile (models.Model):
    user = models.OneToOneField (Пользователь, related_name = 'profile')
    nickname = models.TextField (max_length = 64, null = True, blank = True)
    dob = models.DateField (null = True, blank = True)
    пол = models.CharField (max_length = 1,
                              choices = GENDER_CHOICES, по умолчанию = 'M')
    био = модели.Текстовое поле (max_length = 1024, null = True, blank = True)
    [...]  

Теперь нам нужно убедиться, что соответствующий экземпляр UserProfile создается (или уже существует) каждый раз, когда экземпляр User сохраняется в базе данных. Эй, мы могли бы переопределить метод save на модели User и добиться этого, верно? Возможно, код может выглядеть примерно так:

  def save (self, * args, * kwargs):
    u = super (Пользователь, сам) .save (* args, ** kwargs)
    Профиль пользователя.objects.get_or_create (user_id = u.id)
    return u # save необходимо вернуть объект ʻUser`, помните!  

НО подождите! Модель User происходит от django.contrib.auth , которая является частью самой установки django! Вы действительно хотите отменить это? Я бы точно не рекомендовал это!

Итак, что теперь?

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

Что ж, нам повезло, потому что Django делает именно это. Эти объявления называются «сигналами». Django «испускает» определенные сигналы, чтобы указать, что он достиг определенного этапа выполнения кода.Эти сигналы обеспечивают «точку входа» в его механизм выполнения кода, позволяя вам выполнять свой собственный код в точке, где испускается сигнал. Django также предоставляет вам идентификационные данные отправителя (и другие важные дополнительные данные), чтобы мы могли максимально точно настроить наш «подключаемый» код!

Отлично! Но это все еще не объясняет, КАК ...

Для нашего сценария у нас есть очень удобный сигнал под названием post_save , который генерируется всякий раз, когда экземпляр модели сохраняется в базе данных - даже модель User ! Следовательно, все, что нам нужно сделать, это «получить» этот сигнал и подключить наш собственный код, который будет выполнен в этой точке процесса, т.е.е. точка, в которой новый пользовательский экземпляр имеет , всего было сохранено в базе данных!

  из приемника импорта django.dispatch
из django.core.signals import post_save
из django.contrib.auth.models импортировать пользователя

@receiver (post_save, sender = Пользователь)
def secure_profile_exists (отправитель, ** kwargs):
    если kwargs.get ('created', False):
        UserProfile.objects.get_or_create (пользователь = kwargs.get ('экземпляр'))  

Запутались? Не волнуйся. Давайте попробуем прочитать код построчно, чтобы понять, о чем он говорит.

 > @receiver (post_save, sender = User)  

(NB: я надеюсь, что три строки импорта кажутся очевидными.)

Первая строка фрагмента - это декоратор с именем @receiver . Этот декоратор представляет собой просто ярлык для оболочки, которая вызывает соединение с сигналом post_save . Декоратор также может принимать дополнительные аргументы, которые передаются в сигнал. Например, в этом случае мы указываем аргумент sender = User , чтобы гарантировать, что получатель вызывается только тогда, когда сигнал отправляется моделью User .

Декоратор, по сути, заявляет следующее: «Следите за любым экземпляром модели User , сохраняемым в базе данных, и сообщите Django, что у нас есть приемник , который ожидает выполнения кода, когда такое событие происходит. . "

 > def secure_profile_exists (отправитель, ** kwargs):  

Сейчас мы определяем функцию, которая будет вызываться при перехвате сигнала post_save . Для облегчения понимания и читабельности кода мы назвали эту функцию secure_profile_exists и передаем отправителя сигнала в качестве аргумента этой функции.Мы также передаем функции дополнительные аргументы ключевых слов, и вскоре мы увидим, насколько они будут полезны.

 > если kwargs.get ('created', False):
          UserProfile.objects.get_or_create (пользователь = kwargs.get ('экземпляр'))  

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

Представьте, что вы инструктируете человека у печатного станка (где печатается определенная книга), говоря ему: «Скажите мне, когда каждый опубликованный экземпляр книги выходит из печати.«Тем самым вы обеспечили, чтобы этот человек подошел к вам и проинформировал вас всякий раз, когда копия книги появляется в конце производственной линии печатного станка. А теперь представьте, что этот человек очень эффективен и также приносит с собой копию опубликованная книга, вышедшая из печати.

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

Переменная kwargs является примером сверхэффективности сигнала post_save - она ​​отправляет важную информацию, относящуюся к отправителю сигнала. Обычно сигнал post_save отправляет копию сохраненного экземпляра и логическую переменную created , которая указывает, был ли создан новый экземпляр или был сохранен / обновлен более старый экземпляр. Есть еще несколько вещей, которые включены в словарь kwargs , но именно эти две переменные мы будем использовать для выполнения нашей конечной задачи - создания профиля UserProfile всякий раз, когда создается новый пользователь User .

Таким образом, эта часть нашего фрагмента кода просто проверяет (логическое) значение созданного ключа в словаре kwargs (предполагается, что это False по умолчанию) и создает UserProfile всякий раз, когда он обнаруживает, что новый пользователь был создан ...

... именно это мы и хотели!

Хм ... А где же весь этот код жить? В каком файле?

Согласно официальной документации Django по сигналам:

Вы можете разместить код обработки сигнала и регистрационный код где угодно.Однако вам нужно убедиться, что модуль, в котором он находится, импортируется на ранней стадии, чтобы обработка сигналов была зарегистрирована до отправки каких-либо сигналов. Это делает файл models.py вашего приложения удобным местом для регистрации обработчиков сигналов.

Обратите внимание, что рекомендуемое расположение - models.py . Это, конечно, не означает, что - это место, где хранятся все ваши регистрации сигналов и обработчики. Если вы хотите быть авантюристом, вы можете написать свой код в отдельном файле (скажем, signal.py или что-то подобное) и импортируйте его именно в тот момент, когда ваши сигналы должны быть зарегистрированы / обработаны.

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

Удачи!


ЧТО СЛЕДУЕТ ПРИМЕЧАНИЕ

  1. Обратите внимание, что мы не добавляли никакой дополнительной информации в UserProfile - мы просто создали пустой (но связанный) экземпляр и оставили его для изменения позже.Поскольку мы определили, что большинство из них были определены для приема значений NULL и , наш код по-прежнему будет работать. Однако при желании вы можете использовать другие API-интерфейсы (внутренние и внешние) для получения соответствующих данных для атрибутов (например, псевдоним , bio , dob , , пол и т. Д.) и предварительно заполните их при создании UserProfile - например, извлекая соответствующие данные из профиля социальной сети.

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

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *