Reputation: 818
I am trying to use a pre_delete
signal for the Like
model of my Django app. The Like
model has a Book
foreign key. The Book
model has a num_of_likes
field. Ultimately, I am trying to update this num_of_likes
field from my pre_delete
signal. Just I couldn't do it.
My code will make what the problem is very clear, I think (please pay special attention to the comments and print statements):
books/models.py:
class Book(models.Model):
num_of_likes = models.IntegerField()
likes/models.py:
class Like(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
likes/views.py:
class DeleteLikeView(APIView):
def post(self, request, book):
book = get_object_or_404(Book, id=book)
print(book.num_of_likes) # Prints, say, 10
like = Like.objects.get(user=request.user, book=book)
like.delete() # triggers signal handler below (should update `book.num_of_likes`)
print(book.num_of_likes) # Still prints 10, expected 9 <------ PROBLEM
return ...
likes/signals.py:
@receiver(pre_delete, sender=Like)
def delete_book_like(sender, instance, **kwargs):
print(instance.book.num_of_likes) # Prints 10
instance.book.num_of_likes -= 1
instance.book.save()
print(instance.book.num_of_likes) # Prints 9, as expected
Why does book.num_of_likes
get updated inside delete_book_like
but then changes don't show up in DeleteLikeView
?
Upvotes: 0
Views: 442
Reputation: 73470
The book
in your delete view is a different Python object than the instance.book
in your signal handler. The Python object does not magically learn that the underlying db representation has changed. You could call refresh_from_db
before printing:
book.refresh_from_db()
print(book.num_of_likes)
Or just make num_of_likes
an dynamically evaluated property altogether and you won't have to worry about the integrity of your denormalized data:
class Book(models.Model):
@property
def num_of_likes(self):
return self.like_set.count()
Upvotes: 3