Django сигнал не работает

Django pre_save сигнал не работает

Я протестировал сигнал Django «pre_save» следующими способами, но не смог уловить сигнал ни в одном из них.

Запустите приведенный выше код в оболочке manage.py: Затем я запускаю свой веб-сайт и вижу, что models.save () успешно работает, но функция обратного вызова не запускается.

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

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

Не могли бы вы помочь мне понять, почему сигнал pre_save не работает?

4 ответа

Вы не устанавливаете класс отправителя для одного.

Во-вторых, если вы используете Django 1.3, вы должны использовать новый синтаксис декоратора.

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

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

В примерах 1 и 3 легко понять, почему они не сработали — вы сохраняете в другом процессе (на веб-сайте) то место, где прослушивают ваши приемники сигналов.

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

Источник

Сигналы Django не работают должным образом

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

Моя структура приложения выглядит следующим образом:

Я считаю, что сигналы нужно импортировать как можно раньше, перед моделями, поэтому в верхней части models/__init__.py у меня есть from .signals import * .

Я запускаю сервер отладки в Pycharm с точкой прерывания в функции create_status() , и он никогда не попадает.

Я сделал это неправильно?

Мне кажется, вам просто нужно импортировать helpers/status.py , например, в models/__init__.py

в противном случае ваш сигнал event_status получает значение ok, но обработчик сигнала create_status никогда не подключается Django

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

Я использовал сигналы в некоторых своих проектах, и я всегда импортирую сигналы в __init__.py моего Django APP (в ту же папку, что и settings.py, views.py, urls.py. )

__ __ INIT ру:.

signals.py:

Помните об этом 2 импорта:

    from django.db.models.signals import post_save, pre_delete
    from django.dispatch import receiver

Не забудьте импортировать сигналы

    Чтобы импортировать сигналы, которые необходимо добавить import signals в __init__.py вашего проекта

Используя этот код, эти функции вызываются автоматически Django, когда объект класса Modelname создается или удаляется.

Получатель для созданного объекта называется после, объект создан, а получатель для удаленного объекта называется до, объект удален.

Источник

Документация Django 3.0

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

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

Отправляются до или после вызова метода save() модели.

Отправляются до или после вызова метода delete() модели или delete() класса QuerySet.

Отправляются после изменения ManyToManyField в модели.

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

Полный список этих сигналов, а также описание каждого сигнала, см. в документации по встроенным сигналам .

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

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

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 функцией или методом:

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

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

Читайте также:  Починить дисплей самсунг м31

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

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

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

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

receiver (signal)¶

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

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

Теперь наша функция 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() .

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

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

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

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

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

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

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

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

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

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

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

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.

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

Все сигналы являются экземплярами класса 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, и гарантирует, что сигнал дойдёт до всех получателей. Если произойдёт ошибка в одном из них, экземпляр исключения будет помещён в кортежную пару, для получателя, который соответствует вызываемой ошибке.

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

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

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

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

Источник

Сигналы¶

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

См. документацию на signal dispatcher для получения информации о том, как регистрировать и принимать сигналы.

Модельные сигналы¶

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

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

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

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

На сигналы модели sender модели можно лениво ссылаться при подключении приемника, указывая его полную метку приложения. Например, на модель Question , определенную в приложении polls , можно сослаться как на ‘polls.Question’ . Такой вид ссылки может быть весьма удобен при работе с круговыми зависимостями импорта и заменяемыми моделями.

Читайте также:  Не работает прерыватель дворников газель

pre_init ¶

Когда вы инстанцируете модель Django, этот сигнал посылается в начале метода модели __init__() .

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

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

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

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

Аргумент Значение
sender Question (сам класс)
args [] (пустой список, поскольку не было передано позиционных аргументов для __init__() )
kwargs

post_init ¶

Подобно pre_init, но этот отправляется, когда завершается метод __init__() .

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

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

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

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

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

pre_save ¶

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

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

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

post_save ¶

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

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

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

pre_delete ¶

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

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

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

post_delete ¶

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

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

sender Класс модели. instance

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

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

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

m2m_changed ¶

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

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

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

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

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

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

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

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

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

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

Если мы подключим обработчик следующим образом:

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

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

Аргумент Значение
sender Pizza.toppings.through (промежуточный класс m2m)
instance p (модифицируемый экземпляр Pizza )
action «pre_add» (за ним следует отдельный сигнал «post_add» )
reverse False ( Pizza содержит ManyToManyField , поэтому этот вызов изменяет прямое отношение)
model Topping (класс объектов, добавленных в Pizza )
pk_set (так как к отношению было добавлено только Topping t )
using «default» (так как маршрутизатор по умолчанию отправляет сюда записи)

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

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

Аргумент Значение
sender Pizza.toppings.through (промежуточный класс m2m)
instance t (модифицируемый экземпляр Topping )
action «pre_remove» (за ним следует отдельный сигнал «post_remove» )
reverse True ( Pizza содержит ManyToManyField , поэтому этот вызов изменяет обратное отношение)
model Pizza (класс объектов, удаленных из Topping )
pk_set (так как из отношения было удалено только Pizza p )
using «default» (так как маршрутизатор по умолчанию отправляет сюда записи)

class_prepared ¶

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

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

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

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

Сигналы управления¶

pre_migrate ¶

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

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

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

Указывает, сколько информации manage.py выводит на экран. Подробнее см. флаг —verbosity .

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

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

Например, приложение django.contrib.auth предлагает создать суперпользователя, только если interactive — True .

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

post_migrate ¶

Отправляется в конце команд migrate (даже если миграции не запущены) и flush . Не выдается для приложений, в которых отсутствует модуль models .

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

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

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

Указывает, сколько информации manage.py выводит на экран. Подробнее см. флаг —verbosity .

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

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

Например, приложение django.contrib.auth предлагает создать суперпользователя, только если interactive — True .

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

Например, вы можете зарегистрировать обратный вызов в AppConfig следующим образом:

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

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

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

request_started ¶

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

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

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

request_finished ¶

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

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

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

got_request_exception ¶

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

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

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

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

Сигналы посылаются только тогда, когда running tests .

setting_changed ¶

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

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

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

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

sender Обработчик настроек. setting Название настройки. value Значение настройки после изменения. Для настроек, которые изначально не существуют, в фазе «срыва» value становится None . enter Булево значение; True если настройка применяется, False если восстанавливается.

template_rendered ¶

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

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

sender Объект Template , который был отрисован. template То же, что и отправитель context Context , с помощью которого был отрисован шаблон.

Обертки баз данных¶

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

connection_created ¶

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

Источник

Оцените статью