8

I want to send an email when a specific field is changed in a model. Is it possible? Here is what I am looking for. I have a profile model that includes a BooleanField that when the administrator selects to be true I want to send user an email. I know I could put it in a "def save(self):" but, that fires off an email anytime the model is changed and the field is true. Is there a way to have it only email if the field was changed from False to True?

Charles Sprayberry
  • 7,741
  • 3
  • 41
  • 50

4 Answers4

14

save method is a perfectly good place for what you want to do:

def save(self):
    if self.id:
        old_foo = Foo.objects.get(pk=self.id)
        if old_foo.YourBooleanField == False and self.YourBooleanField == True:
            send_email()
    super(Foo, self).save()
Sergey Golovchenko
  • 18,203
  • 15
  • 55
  • 72
  • I might change the if statement to this: if not old.field == self.field: – ShawnMilo Jul 21 '09 at 16:21
  • He wants to send email only when the value changed from False to True. So checking that values are not equal is not enough. – Sergey Golovchenko Jul 21 '09 at 16:37
  • Was looking for a way to trigger any action when a model is changed ... looks like this is it. Thanks. – Matt Miller Sep 25 '09 at 17:42
  • 4
    The one disadvantage to overriding save here is this: the send_email() call will be blocking until it finishes executing. The user might have to wait a non-trivial amount of time, before the page loads again. If that's not a concern, then this is fine; otherwise, I'd suggest the signal approach mentioned below. – mkelley33 Jan 28 '12 at 23:23
  • I retract my statement about the signal approach after reading the comment about the changing value. See also: http://stackoverflow.com/questions/1355150/django-when-saving-how-can-you-check-if-a-field-has-changed See the answer with > 20 votes by Josh. You might want to look at something like django-celery-email if you think wait times for sending mail might be a problem. – mkelley33 Jan 29 '12 at 00:26
6

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):
   flag = models.BooleanField()

@receiver(pre_save, sender=MyModel)
def send_email_if_flag_enabled(sender, instance, **kwargs):
    if instance.previous_instance().flag == False and instance.flag == True:
        # send email
Robert Kajic
  • 8,689
  • 4
  • 44
  • 43
0

Something like this could help and only sends an email when change from false to true

#models.py
from django.contrib.auth.models import User
from django.db.models import signals
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import pre_save
from django.conf import settings
from django.core.mail import send_mail

#signal used for is_active=False to is_active=True
@receiver(pre_save, sender=User, dispatch_uid='active')
def active(sender, instance, **kwargs):
    if instance.is_active and User.objects.filter(pk=instance.pk, is_active=False).exists():
        subject = 'Active account'
        mesagge = '%s your account is now active' %(instance.username)
        from_email = settings.EMAIL_HOST_USER
        send_mail(subject, mesagge, from_email, [instance.email], fail_silently=False)
M. Gar
  • 889
  • 4
  • 16
  • 33
-1

Use hook a function with your models post_save using django signals (http://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.post_save)

In that function use standard django mailing: http://docs.djangoproject.com/en/dev/topics/email/

sharjeel
  • 5,825
  • 7
  • 34
  • 49