0

Here is a project I've created to practice, in my models.py,

class Post(models.Model):
   title = models.CharField(max_length = 140)
   author = models.ForeignKey(User, on_delete=models.CASCADE)
   votes = models.BigIntegerField(default=0, blank=True)


class Vote(models.Model):
   user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='voter')
   post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='vpost')

 @receiver(post_save, sender=Vote)
 def update_votes(sender, **kwargs):
    # # ??

Here I have a Voteform with that user can vote any particular post. That part works well.

Here is my question, whenever a user votes a particular post, I want votes field in Post model to increase as well.

I know I can show it with {{post.vpost.count}} in my html. But I want that increment here.

Other way I have tried,

class Vote(models.Model):
   user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='voter')
   post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='vpost')

 def update_votes(self):
     p = self.post
     p.votes += 1
     p.save()

This one only works once, not working from second time, so I want to use signal method. So how can I update the vote field in Post model using signal?

Bidhan Majhi
  • 1,320
  • 1
  • 12
  • 25
  • I don't think this is something you'd want to store in a separate field when you can get it with a simple `post.vote_set.count()` call, without the hassle of keeping the count up to date. The only reason to do that would be demonstrably insufficient performance owing to the added query. Is that the case here? – Endre Both Feb 16 '19 at 17:41
  • I know about that, also mentioned in the question as well. This in one of the cases that I was practicing just for my learning. – Bidhan Majhi Feb 17 '19 at 06:24

1 Answers1

1

Nearly there. I would rename Post.votes to Post.votes_count as votes indicates a reverse relationship.

@receiver(post_save, sender=Vote)
def update_votes(sender, instance, **kwargs):
    post = instance.post
    post.votes_count += 1
    post.save()

Although you might want to make sure that the count is correct, by introducing another query:

@receiver(post_save, sender=Vote)
def update_votes(sender, instance, **kwargs):
    post = instance.post
    post.votes_count = post.votes_set.all().count()
    post.save()

You might also want to do this when/if a Vote is deleted to make sure the count is correct.

Bear in mind you could also just do this in the Vote's save method instead of needing signals.

You could also do this as a cronjob or task depending on your circumstances

Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177