You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Django电影评论应用:如何实现影片平均评分展示?

解决影片平均评分计算问题

嘿,我看到你的问题了——你现在的代码是在给单个评论计算“平均评分”,这当然得不到影片的整体平均分啦!让我帮你把逻辑理顺:

问题出在哪?

你当前的ToplistListView基于Review模型,并且用annotate(Avg('rating'))给每条评论加了个avg_rating字段。但每条评论本身只有一个评分,所以这个“平均值”其实就是评论自己的评分,排序也只是按单条评论的分数来,完全没涉及到影片的汇总计算。

我们需要切换思路:以影片为单位,汇总它所有评论的评分,计算平均值

修正后的代码

1. 更新views.py

把视图的查询对象改成Film,并按影片分组计算平均评分:

from django.db.models import Avg, Coalesce
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from .models import Film

class ToplistListView(LoginRequiredMixin, ListView):
    model = Film  # 改为基于影片模型查询
    template_name = "board/toplist.html"
    context_object_name = "films"
    
    def get_queryset(self):
        # 为每个影片计算所有评论的平均评分
        # 用Coalesce处理无评论的影片,默认显示0分
        return Film.objects.annotate(
            avg_rating=Coalesce(Avg('review_set__rating'), 0)
        ).order_by('-avg_rating')  # 按平均评分降序排列

2. (可选)优化models.py让关联更直观

如果你觉得review_set这个名字不够友好,可以给Review的外键添加related_name

# models.py中的Review模型
class Review(models.Model):
    # ... 其他字段不变
    reviewed_film = models.ForeignKey(Film, on_delete=models.CASCADE, related_name='reviews')

这样之后,views里的annotate可以改成Avg('reviews__rating'),模板里调用评论列表也更清晰。

3. 模板中展示平均评分

toplist.html里,你可以直接通过影片对象的avg_rating属性获取平均值:

{% for film in films %}
    <div class="film-card">
        <h2>{{ film.title }}</h2>
        <p>🎬 平均评分: {{ film.avg_rating|floatformat:1 }}</p>
        <p>💬 评论数: {{ film.review_set.count }}</p>
        <!-- 如果你设置了related_name='reviews',就改成film.reviews.count -->
    </div>
{% endfor %}

关键知识点

  • annotate()结合Avg():当对父模型(Film)使用annotate(Avg('子模型__字段'))时,Django会自动按父模型分组,计算每个父对象关联的所有子对象的字段平均值。
  • Coalesce():用来处理没有评论的影片,把null值转换成0,避免页面显示空白或者报错。
  • 反向关联:Django中外键的反向关联默认是子模型名_set,比如FilmReview的反向关联是review_set,设置related_name可以自定义这个名称。

这样修改后,你就能看到每个影片的真实平均评分啦!比如有两条1分和5分评论的影片,会显示3.0的平均分。

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

火山引擎 最新活动