You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中基于Rating模型更新Product模型的评分统计字段

Django 实现提交评分自动更新产品统计字段方案

方案一:使用Django信号(更推荐,解耦性更好)

这种方式可以统一处理评分新增、修改、删除三个场景的统计更新,不需要耦合到模型业务逻辑里。

  1. 首先在Rating模型所在的app下新建signals.py,或者直接在models.py中添加如下代码:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.db.models import Avg, Count
from .models import Rating

@receiver(post_save, sender=Rating)
@receiver(post_delete, sender=Rating)
def update_product_rating_stats(sender, instance, **kwargs):
    # 获取关联的产品对象
    product = instance.product
    # 聚合计算当前产品的总评分数量和平均评分
    rating_stats = product.product_ratings.aggregate(
        total_count=Count('id'),
        avg_rating=Avg('product_rating')
    )
    # 更新产品字段,平均评分按IntegerField要求做四舍五入处理
    product.total_rating_count = rating_stats['total_count']
    product.avg_rating = round(rating_stats['avg_rating']) if rating_stats['avg_rating'] else None
    # 仅更新指定字段,提高效率避免触发其他无关逻辑
    product.save(update_fields=['total_rating_count', 'avg_rating'])
  1. 如果你将信号写在单独的signals.py中,需要到对应app的apps.py中注册信号才会生效:
from django.apps import AppConfig

class YourAppNameConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = '你的app名称'

    def ready(self):
        import 你的app名称.signals

方案二:重写Rating模型的save/delete方法

适合小型项目,不需要额外注册信号,直接在Rating模型中添加两个方法即可:

class Rating(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='product_ratings')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_rating')
    product_rating = models.IntegerField(verbose_name='Rating', blank=False)
    product_comment = models.TextField(verbose_name='Comment', blank=False)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        # 保存评分后更新产品统计
        rating_stats = self.product.product_ratings.aggregate(
            total_count=Count('id'),
            avg_rating=Avg('product_rating')
        )
        self.product.total_rating_count = rating_stats['total_count']
        self.product.avg_rating = round(rating_stats['avg_rating']) if rating_stats['avg_rating'] else None
        self.product.save(update_fields=['total_rating_count', 'avg_rating'])

    def delete(self, *args, **kwargs):
        product = self.product
        super().delete(*args, **kwargs)
        # 删除评分后更新产品统计
        rating_stats = product.product_ratings.aggregate(
            total_count=Count('id'),
            avg_rating=Avg('product_rating')
        )
        product.total_rating_count = rating_stats['total_count']
        product.avg_rating = round(rating_stats['avg_rating']) if rating_stats['avg_rating'] else None
        product.save(update_fields=['total_rating_count', 'avg_rating'])

注意事项

  • 当前Product模型中avg_rating为IntegerField,所以做了四舍五入取整处理,如果你需要保留小数可以将字段改为FloatField或者DecimalField,调整计算逻辑即可。
  • 以上两种方案仅在单条评分增删改时生效,如果有批量操作评分的需求,需要手动调用统计更新逻辑。

内容的提问来源于stack exchange,提问作者Nahidujjaman Hridoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 23:27:03