In my DJango application I'd like to implement a system so that when the email field in my jmodel, MyModel is changed, an email is sent to that email address. I have a ModelForm on this Model of mine. How and how should I implement this?

  1. Should I override the save() method of my ModelForm and send the email there?
  2. Should I try and try an trap some kind of model updated signal and send the email there — if so, how? What signal shoudl I be trapping?

What is a good way to check that the email was changed. This itself is a trivial thing to implement but I'd like the code to reside it it's rightful place.

Thanks

Checking if a field was changed: Django: When saving, how can you check if a field has changed?

score:1

Accepted answer

I wouldn't follow the advice of the referenced SO question. It got 18 upvotes but it would appear upvotes aren't everything ;). Actually, it's probably just dated info (2009).

It's far better to use a pre_save signal to do this, which requires absolutely zero changes to your model and therefore doesn't have any negative consequences such as the answer your referenced has.

Essentially, in your receiver method, you look up the instance object from the database. Since this is pre-save, the database hasn't been changed yet. As a result, you can then compare instance.some_field with obj.some_field and see if they're different.

@receiver(pre_save, sender=MyModel)
def send_email_if_changed(sender, instance, **kwargs):
    try:
        obj = MyModel.objects.get(pk=instance.pk)
    except MyModel.DoesNotExist:
        pass # It's new, so email hasn't technically changed, but you might want to do something else here.
    else:
        if not obj.email == instance.email: # Email has changed
            # send email

score:2

You can use django-model-changes to do this without an additional database lookup:

from django.db import models
from django.dispatch import receiver
from django_model_changes import ChangesMixin

class MyModel(ChangesMixin, models.Model):
   # your model

@receiver(pre_save, sender=MyModel)
def send_email_if_changed(sender, instance, **kwargs):
    if 'email' in instance.changes():
        # send email

Related Query