尝试以最干净的方式向我的应用添加电子邮件通知。当模型的某些字段发生变化时,应该向用户发送通知。这是我以前的解决方案:
from django.contrib.auth import User
class MyModel(models.Model):
user = models.ForeignKey(User)
field_a = models.CharField()
field_b = models.CharField()
def save(self, *args, **kwargs):
old = self.__class__.objects.get(pk=self.pk) if self.pk else None
super(MyModel, self).save(*args, **kwargs)
if old and old.field_b != self.field_b:
self.notify("b-changed")
# Sevelar more events here
# ...
def notify(self, event)
subj, text = self._prepare_notification(event)
send_mail(subj, body, settings.DEFAULT_FROM_EMAIL, [self.user.email], fail_silently=True)
当我有一个或两个通知类型时,这很好用,但之后在我的save()
方法中有这么多代码感觉不对。所以,我将代码更改为基于信号:
from django.db.models import signals
def remember_old(sender, instance, **kwargs):
"""pre_save hanlder to save clean copy of original record into `old` attribute
"""
instance.old = None
if instance.pk:
try:
instance.old = sender.objects.get(pk=instance.pk)
except ObjectDoesNotExist:
pass
def on_mymodel_save(sender, instance, created, **kwargs):
old = instance.old
if old and old.field_b != instance.field_b:
self.notify("b-changed")
# Sevelar more events here
# ...
signals.pre_save.connect(remember_old, sender=MyModel, dispatch_uid="mymodel-remember-old")
signals.post_save.connect(on_mymodel_save, sender=MyModel, dispatch_uid="mymodel-on-save")
好处是我可以将事件处理程序分成不同的模块,减小models.py
的大小,我可以单独启用/禁用它们。缺点是这个解决方案是更多的代码和信号处理程序与模型本身分开,不知情的读者可以完全错过它们。所以,同事们,你觉得它值得吗?
答案 0 :(得分:4)
我认为这是一个好主意。来自最新DjangoCon的"Custom Signals for Uncoupled Design" talk是Django中信号可能和适当的重要资源。
答案 1 :(得分:3)
我认为在这里使用信号是一个很好的设计决策。通知不是保存的一部分,它是保存的结果。处理这些类型的后果是Django提供信号的原因。