В чем разница между использованием сигналов django и вызовом метода?
Я пытаюсь реализовать функцию, которая отправляет уведомление всем записям сотрудников всякий раз, когда публикуется новая запись документа. В моделях мне все еще нужно импортировать функцию получателя, потому что моя модель отправителя находится в другом проекте:
функция приемника (находится в другом приложении в проекте):
def new_document_version_published(sender, instance, **kwargs):
print("New version of document published!")
print(sender)
print(instance)
# Get all employees
employees = []
# Send notifications to employees
buttons = [NotificationButton(button_text="New version of document", value="Ok", style="primary")]
notifyUsers("A new version of the document has been published", buttons, employees, [])
отправитель (живет в другом приложении в проекте):
from django.db.models.signals import post_save
from api.views import new_document_version_published
class DocumentVersion:
...
def save(self, *args, **kw):
if self.pk is not None:
orig = DocumentVersion.objects.get(pk=self.pk)
if orig.date_published != self.date_published:
print('date_published changed')
notify_employees()
if orig.date_approved != self.date_approved:
print('date_approved changed')
super(DocumentVersion, self).save(*args, **kw)
def notify_employees():
post_save.connect(new_document_version_published, sender=DocumentVersion)
Я знаю, что что-то не так с моей реализацией, потому что я не понимаю, в чем разница между использованием сигнала и просто импортом и вызовом функции приемника. Любая помощь приветствуется!
В чем разница
Вызов функции делает вызывающую функцию зависимой от функции-приемника (или, по крайней мере, осведомленной о ней), в то время как использование сигналов Django делает функцию-приемник зависимой от сигнала, вызываемого ее вызывающим(и).
From https://docs.djangoproject.com/en/3.2/topics/signals/:
... помогает развязанным приложениям получать уведомления о действиях, происходящих в других частях фреймворка. В двух словах, сигналы позволяют определенным отправителям уведомлять набор получателей о том, что произошло какое-то действие. Они особенно полезны, когда многие части кода могут быть заинтересованы в одних и тех же событиях.
Когда использовать сигналы Django
From https://www.django-antipatterns.com/antipattern/signals.html:
Сигналы влекут за собой множество проблем и непредвиденных последствий. ...
Часто лучше избегать использования сигналов. Можно реализовать много логики без сигналов. ...
Сигналы все еще могут быть хорошим решением, если вы хотите обрабатывать события, поднимаемые сторонним приложением Django. ...
Как выглядит эта разница
Вызов функции
Предварительное сохранение:
# notify_employees() # Replace this
new_document_version_published(self.__class__, self) # with this
Пост-сохранение:
class DocumentVersion(models.Model):
...
def save(self, *args, **kw):
orig = None # ......... # Add this
if self.pk is not None:
orig = DocumentVersion.objects.get(pk=self.pk)
if orig.date_published != self.date_published:
print('date_published changed')
# notify_employees() # Replace this
if orig.date_approved != self.date_approved:
print('date_approved changed')
super(DocumentVersion, self).save(*args, **kw)
if orig and orig.date_published != self.date_published: # with this
new_document_version_published(self.__class__, self) #
Использование сигналов Django
Поскольку сигнал Django post_save
не передает orig
, давайте воспользуемся пользовательским сигналом:
- Определите сигнал.
- Пошлите сигнал.
- Реализуйте функцию приемника.
- Подключите функцию приемника, обычно там, где определена функция приемника.
Пост-сохранение:
post_save_published = Signal() # Add this
class DocumentVersion(models.Model):
...
def save(self, *args, **kw):
orig = None # ......... # Add this
if self.pk is not None:
orig = DocumentVersion.objects.get(pk=self.pk)
if orig.date_published != self.date_published:
print('date_published changed')
# notify_employees() # Replace this
if orig.date_approved != self.date_approved:
print('date_approved changed')
super(DocumentVersion, self).save(*args, **kw)
if orig and orig.date_published != self.date_published: # with this
post_save_published.send(sender=self.__class__, instance=self) #
def new_document_version_published(sender, instance, **kwargs):
# ...
post_save_published.connect(new_document_version_published, sender=DocumentVersion) # Add this