Identify the changed fields in django post_save signal
If you want to compare state before and after save action, you can use pre_save
signal which provide you instance as it should become after database update and in pre_save you can read current state of instance in database and perform some actions based on difference.
from django.db.models.signals import pre_save
from django.dispatch import receiver
@receiver(pre_save, sender=MyModel)
def on_change(sender, instance: MyModel, **kwargs):
if instance.id is None: # new object will be created
pass # write your code here
else:
previous = MyModel.objects.get(id=instance.id)
if previous.field_a != instance.field_a: # field will be updated
pass # write your code here
Ussually it's better to override the save method than using signals.
From Two scoops of django: "Use signals as a last resort."
I agree with @scoopseven answer about caching the original value on the init, but overriding the save method if it's possible.
class Mode(models.Model):
name = models.CharField(max_length=5)
mode = models.BooleanField()
__original_mode = None
def __init__(self, *args, **kwargs):
super(Mode, self).__init__(*args, **kwargs)
self.__original_mode = self.mode
def save(self, force_insert=False, force_update=False, *args, **kwargs):
if self.mode != self.__original_mode:
# then do this
else:
# do that
super(Mode, self).save(force_insert, force_update, *args, **kwargs)
self.__original_mode = self.mode
UPDATE IF YOU NEED SIGNALS
Just in case you really need signals because you need a decoupled app or you can't simply override the save() method, you can use pre_save signal to 'watch' previous fields
@receiver(pre_save, sender=Mode)
def check_previous_mode(sender, instance, *args, **kwargs):
original_mode = None
if instance.id:
original_mode = Mode.objects.get(pk=instance.id).mode
if instance.mode != original_mode:
# then do this
else:
# do that
The problem with this is that you make changes before, so if save() has a problem you could have some issues later. So to fix that issue, you can store the original value on the pre_save and use on post_save.
@receiver(pre_save, sender=Mode)
def cache_previous_mode(sender, instance, *args, **kwargs):
original_mode = None
if instance.id:
original_mode = Mode.objects.get(pk=instance.id).mode
instance.__original_mode = original_mode:
@receiver(post_save, sender=Mode)
def post_save_mode_handler(sender, instance, created, **kwargs):
if instance.__original_mode != instance.original_mode:
# then do this
else:
# do that
The problem with signals and this approach also is that you need one more query to check previous values.