Django重写模型save方法统计点赞数到total_likes字段报错如何解决
问题修复方案
你代码里存在以下几处错误:
- 缩进错误:
save方法没有定义在Question类的内部,属于全局函数,不会被模型调用 - 多对多字段调用错误:你给
likes字段显式设置了related_name='likes',不需要加_set后缀,直接调用self.likes.count()即可,likes_set是不存在的属性,会触发报错 - 逻辑缺陷:多对多关系的修改(用户点赞/取消赞操作)默认不会触发
Question模型的save方法,即便修正上述两个错误,total_likes也不会在点赞操作后自动更新 - 额外小问题:代码中直接使用了
impression_choices但没有提前定义,也会触发报错
修复方案1:保留total_likes存储字段,用信号同步
适合点赞量大、需要对点赞数字段做索引/过滤的场景:
from django.db import models from django.contrib.auth.models import User from django.db.models.signals import m2m_changed from django.dispatch import receiver # 提前定义impression选项,可根据业务需求自行调整 impression_choices = ( ('positive', '好评'), ('neutral', '中立'), ('negative', '差评'), ) class Question(models.Model): text = models.TextField() voters = models.ManyToManyField(to=User, blank=True, related_name='voted_questions') impression = models.CharField(max_length=30, choices=impression_choices, blank=True, null=True) date_created = models.DateTimeField(auto_now_add=True) # 修改related_name为更合理的命名,避免User侧属性歧义 likes = models.ManyToManyField(to=User, related_name='liked_questions', blank=True) total_likes = models.IntegerField(default=0) def __str__(self): return self.text # 把save方法移到类内部 def save(self, *args, **kwargs): self.total_likes = self.likes.count() super().save(*args, **kwargs) # 新增多对多变更信号,点赞/取消赞时自动更新总点赞数 @receiver(m2m_changed, sender=Question.likes.through) def update_likes_count(sender, instance, action, **kwargs): # 只有在添加、移除、清空点赞操作后才更新 if action in ["post_add", "post_remove", "post_clear"]: instance.total_likes = instance.likes.count() instance.save(update_fields=['total_likes']) class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) text = models.CharField(max_length=20) votes = models.IntegerField(blank=True, default=0) def __str__(self): return self.text
修复方案2:轻量场景直接用动态属性,无需存储
如果项目点赞量不大,不需要对点赞数字段做索引/过滤,可以直接删掉total_likes存储字段,用property动态计算点赞数,完全不需要考虑数据同步问题:
class Question(models.Model): text = models.TextField() voters = models.ManyToManyField(to=User, blank=True, related_name='voted_questions') impression = models.CharField(max_length=30, choices=impression_choices, blank=True, null=True) date_created = models.DateTimeField(auto_now_add=True) likes = models.ManyToManyField(to=User, related_name='liked_questions', blank=True) # 新增动态属性,访问时实时计算点赞数 @property def total_likes(self): return self.likes.count() def __str__(self): return self.text
内容的提问来源于stack exchange,提问作者Muhammad Arsalan
相关产品推荐
相关产品推荐

