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

如何在Django中实现商品的评论数量统计与平均评分计算?

解决方案

方案1:动态计算属性(无需修改数据库)

直接在Product模型中添加属性方法,每次访问时实时计算评论数和平均评分,适合数据量较小的场景:

修改Product模型代码如下:

class Product(models.Model):
    name = models.CharField(max_length=200, null=True, blank=True)
    brand = models.CharField(max_length=200, null=True, blank=True)
    image = models.ImageField(null=True, blank=True, default='placeholder.png')
    description = models.TextField(null=True, blank=True)
    rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
    price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
    countInStock = models.IntegerField(null=True, blank=True, default=0)
    id = models.UUIDField(default=uuid.uuid4, max_length=36, unique=True, primary_key=True, editable=False)

    @property
    def numReviews(self):
        # 通过反向关联查询当前商品的评论数量
        return self.review_set.count()

    @property
    def averageRating(self):
        reviews = self.review_set.all()
        total = reviews.count()
        if total == 0:
            return 0.0
        # 计算平均评分并保留两位小数
        total_rating = sum(review.rating for review in reviews)
        return round(total_rating / total, 2)

    def __str__(self):
        return str(self.name)

使用时直接像访问普通字段一样调用:product.numReviews、product.averageRating。

方案2:数据库存储+信号自动更新(适合大数据量)

如果商品和评论数量较多,实时计算会影响性能,可以把评论数和平均评分存到数据库,通过Django信号在评论增删改时自动更新:

步骤1:修改Product模型,添加对应字段

class Product(models.Model):
    name = models.CharField(max_length=200, null=True, blank=True)
    brand = models.CharField(max_length=200, null=True, blank=True)
    image = models.ImageField(null=True, blank=True, default='placeholder.png')
    description = models.TextField(null=True, blank=True)
    rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
    price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
    countInStock = models.IntegerField(null=True, blank=True, default=0)
    id = models.UUIDField(default=uuid.uuid4, max_length=36, unique=True, primary_key=True, editable=False)
    # 添加存储评论数和平均评分的字段
    numReviews = models.IntegerField(default=0, null=True, blank=True)
    averageRating = models.DecimalField(max_digits=3, decimal_places=2, default=0.0, null=True, blank=True)

    def __str__(self):
        return str(self.name)

步骤2:添加信号处理逻辑

在模型文件末尾添加以下代码:

from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver

# 监听评论的保存和删除事件,更新商品的评论统计
@receiver([post_save, post_delete], sender=Review)
def update_product_review_stats(sender, instance, **kwargs):
    product = instance.product
    if not product:
        return
    # 查询当前商品的所有评论
    reviews = product.review_set.all()
    total_reviews = reviews.count()
    # 更新评论数
    product.numReviews = total_reviews
    # 更新平均评分
    if total_reviews > 0:
        total_rating = sum(review.rating for review in reviews)
        product.averageRating = round(total_rating / total_reviews, 2)
    else:
        product.averageRating = 0.0
    product.save()

步骤3:注册信号(可选)

如果信号没有自动生效,需要在app的apps.py中注册:

from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app_name'

    def ready(self):
        import your_app_name.models  # 导入信号所在的模型文件

记得在settings.py中把APP配置改成这个自定义的类。

方案3:查询时聚合(视图层处理)

如果只是在特定查询场景需要统计数据,可以在查询Product时使用annotate直接聚合,无需修改模型:

在视图中使用以下代码查询:

from django.db.models import Count, Avg

# 查询所有商品,并附带评论数和平均评分
products = Product.objects.annotate(
    numReviews=Count('review', distinct=True),
    averageRating=Avg('review__rating')
)

这样查询出来的每个product对象都会带有numReviews和averageRating属性,适合一次性批量查询的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:55:21