Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How to access original (unmodified) instance in post_save signal

I want to do a data denormalization for better performance, and put a sum of votes my blog post receives inside Post model:

class Post(models.Model):     """ Blog entry """     author          = models.ForeignKey(User)     title           = models.CharField(max_length=255)     text            = models.TextField()     rating          = models.IntegerField(default=0) # here is the sum of votes!  class Vote(models.Model):     """ Vote for blog entry """     post            = models.ForeignKey(Post)     voter           = models.ForeignKey(User)     value           = models.IntegerField() 

Ofcourse, I need to keep Post.rating value actual. Nornally I would use database triggers for that, but now I've decided to make a post_save signal (to reduce database process time):

# vote was saved @receiver(post_save, sender=Vote) def update_post_votes(sender, instance, created, **kwargs):     """ Update post rating """     if created:         instance.post.rating += instance.value         instance.post.save()     else:         # if vote was updated, we need to remove the old vote value and add the new one         # but how...? 

How can I access the instance value before it was saved? In database triggers, i would have OLD and NEW predefines for this, but is there something like this in post_save signals?

UPDATE

The solution based on Mark's the answer:

# vote was saved @receiver(pre_save, sender=Vote) def update_post_votes_on_save(sender, instance, **kwargs):     """ Update post rating """     # if vote is being updated, then we must remove previous value first     if instance.id:         old_vote = Vote.objects.get(pk=instance.id)         instance.post.rating -= old_vote.value     # now adding the new vote     instance.post.rating += instance.value     instance.post.save() 
like image 723
Silver Light Avatar asked Apr 07 '11 14:04

Silver Light


1 Answers

I believe post_save is too late to retrieve the unmodified version. As the name implies the data has already been written to the db at that point. You should use pre_save instead. In that case you can retrieve the model from the db via pk: old = Vote.objects.get(pk=instance.pk) and check for differences in the current instance and the previous instance.

like image 140
Mark Lavin Avatar answered Sep 23 '22 02:09

Mark Lavin