开发者

Is it approproate it use django signals within the same app

开发者 https://www.devze.com 2022-12-26 23:11 出处:网络
Trying to add email notification to my app in the cleanest way possible.When certain fields of a model change, app should send a notification to a user.Here\'s my old solution:

Trying to add email notification to my app in the cleanest way possible. When certain fields of a model change, app should send a notification to a user. Here's my old solution:

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.fi开发者_如何学Goeld_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)

This worked fine while I had one or two notification types, but after that just felt wrong to have so much code in my save() method. So, I changed code to signal-based:

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")

The benefit is that I can separate event handlers into different module, reducing size of models.py and I can enable/disable them individually. The downside is that this solution is more code and signal handlers are separated from model itself and unknowing reader can miss them altogether. So, colleagues, do you think it's worth it?


I think it's a good idea. The "Custom Signals for Uncoupled Design" talk from the most recent DjangoCon is a great resource of what is possible and appropriate with signals in Django.


I think using signals here is a good design decision. The notification isn't part of the save, it's a consequence of the save. Dealing with these types of consequences is the reason Django provides signals.

0

精彩评论

暂无评论...
验证码 换一张
取 消