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

如何利用外键从父表计算子表值:教授满意度平均值计算问题

解决方案:计算每个教授的满意度平均值

问题根源

你的代码存在几个关键错误:

  1. 反向关联名称错误:Evaluation模型的ForeignKey设置了related_name='evaluation_names',所以教授对象的反向关联属性是evaluation_names,而非默认的evaluation_set,之前的代码误用了evaluation_set导致无法正确关联。
  2. DetailView场景误用查询范围:ProfessorDetail是单个教授的详情页,不需要查询所有教授,应该针对当前展示的教授计算平均值。
  3. 聚合方法使用错误:用prefetch_related无法实现聚合计算,平均值需要通过annotate(批量给查询集对象加聚合值)或aggregate(单个对象的聚合结果)来实现。

修正后的代码实现

1. 单个教授详情页(DetailView)

修改views.py的get_context_data方法,针对当前教授计算平均值:

from django.db.models import Avg

class ProfessorDetail(generic.DetailView):
    model = Professor
    context_object_name = "professor_detail"
    template_name = "professors/professor_detail.html"

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        # 获取当前详情页的教授对象
        current_professor = self.get_object()
        # 计算该教授的满意度平均值,处理无评价时返回0
        avg_result = current_professor.evaluation_names.aggregate(avg_satisfaction=Avg('satisfaction'))
        context['avg_satisfaction'] = avg_result['avg_satisfaction'] or 0
        return context

对应的模板professors/professor_detail.html简化为:

<p>当前教授平均满意度:{{ avg_satisfaction }}</p>

2. 教授列表页(批量显示平均值)

如果需要在列表页展示所有教授的平均值,修改ListView的查询集:

from django.db.models import Avg

class ProfessorList(generic.ListView):
    model = Professor
    context_object_name = "professors"
    template_name = "professors/professor_list.html"

    def get_queryset(self):
        # 给每个教授标注对应的满意度平均值
        return Professor.objects.annotate(avg_satisfaction=Avg('evaluation_names__satisfaction'))

列表模板professors/professor_list.html:

{% for professor in professors %}
    <div>
        <h3>{{ professor.name }}</h3>
        <p>平均满意度:{{ professor.avg_satisfaction|default:"暂无评价" }}</p>
    </div>
{% endfor %}

对之前尝试的错误分析

  1. 第一种写法Professor.objects.all().evaluation_set.all().annotate(...):
    • Professor.objects.all()返回的是教授查询集,不能直接调用evaluation_set,且evaluation_set不是正确的反向关联名称。
  2. 第二种写法Professor.objects.prefetch_related().all().annotate(...):
    • prefetch_related未指定正确的关联名称evaluation_names,且annotate的字段路径错误,应该是evaluation_names__satisfaction。
  3. 第三种写法用Prefetch预取关联:
    • prefetch_related的作用是预取关联对象以减少数据库查询,不能用来计算父对象的聚合平均值,属于用法场景错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:50:29