Django-pre_delete信号未更新实例的外键字段

问题描述

我正在尝试为我的Django应用程序的pre_delete模型使用Like信号。 Like模型具有一个Book外键。 Book模型具有一个num_of_likes字段。最终,我尝试根据我的num_of_likes信号更新此pre_delete字段。只是我做不到。

我认为我的代码会使问题很清楚(请特别注意注释和打印语句):

books / models.py

class Book(models.Model):
    num_of_likes = models.IntegerField()

喜欢/models.py

class Like(models.Model):
    user = models.ForeignKey(User)
    book = models.ForeignKey(Book)

喜欢/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 ...

喜欢/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

为什么book.num_of_likesdelete_book_like内部得到更新,但是更改却没有显示DeleteLikeView中?

解决方法

删除视图中的book与信号处理程序中的instance.book是不同的 Python对象。 Python对象无法神奇地得知基础数据库表示形式已更改。您可以在打印前致电refresh_from_db

 book.refresh_from_db()
 print(book.num_of_likes)

或者只需将num_of_likes设置为动态评估的属性,就不必担心非规范化数据的完整性:

class Book(models.Model):
    @property
    def num_of_likes(self):
        return self.like_set.count()