views:

227

answers:

3

I need to detect when some of the fields of certain model have changed in the admin, to later send notifications depending on which fields changed and previous/current values of those fields.

I tried using a ModelForm and overriding the save() method, but the form's self.cleaned_data and seld.instance already have the new values of the fields.

A: 

What you'll need to do is get an extra copy of the object you're working on from the database inside the save method before fully saving it. Example:

class MyModel(models.Model):
    field1 = models.CharField(max_length=50)

    def save(self):
        if self.id:
            try:
                old = MyModel.objects.get(pk=self.id)
                if old.field1 != self.field1:
                    # Process somehow
            except MyModel.DoesNotExist:
                pass
        super(MyModel, self).save()
Adam
I also came up with something like this, (retrieve the object from the DB before it's saved and compare it with the copy that is about to be saved) but I would like to save the extra query.
Mandx
+1  A: 

In order to get differences of two model instances, you can also use this function. It compare to model instances and returns dictionary of changes.

Dominik Szopa
It's useful! But seems that it isn't aware of related fields. For my purposes, adding or deleting a relationship (one-to-many or many-to-many) is also a change of the object.
Mandx
+3  A: 

To avoid extra DB lookup, I modified constructor to remember initial value and use this in save method later:

class Package(models.Model):
    feedback = models.IntegerField(default = 0, choices = FEEDBACK_CHOICES)
    feedback_time = models.DateTimeField(null = True)

    def __init__(self, *args, **kw):
        super(Package, self).__init__(*args, **kw)
        self._old_feedback = self.feedback

    def save(self, force_insert=False, force_update=False, *args, **kwargs):
        if not force_insert and self.feedback != self._old_feedback:
            self.feedback_time = datetime.utcnow()
        return super(Package, self).save(force_insert, force_update, *args, **kwargs)
Michal Čihař