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

在Django(PostgreSQL)中从Employee模型获取员工多份评估平均分

问题与解决方案

问题场景

现有以下Django模型(注:原模型存在两处拼写错误,已修正):

class Employee(models.Model):
    name = models.CharField(max_length=100)

class Evaluation(models.Model):
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
    question1 = models.PositiveIntegerField(default=0)
    question2 = models.PositiveIntegerField(default=0)

员工有多份评估记录,每份记录包含两个问题的得分。当前可以通过Evaluation.objects.annotate(score=F('question1') + F('question2'))获取单份评估的总分,但需要直接从Employee模型查询出每个员工所有评估的平均分。

尝试过两种写法均报错:

  1. 使用普通子查询时,员工有多份评估会触发错误:
from django.db.models import Avg, F, OuterRef, Subquery

score_subquery = Evaluation.objects.annotate(score=F('question1') + F('question2')).filter(employee_id=OuterRef('pk')).values('score')
Employee.objects.annotate(avg_score=Avg(Subquery(score_subquery)))

错误信息:

more than one row returned by a subquery used as an expression

  1. 改用ArraySubquery适配多行结果,却因PostgreSQL限制报错:
from django.db.models import Avg, F, OuterRef, ArraySubquery

score_subquery = Evaluation.objects.annotate(score=F('question1') + F('question2')).filter(employee_id=OuterRef('pk')).values('score')
Employee.objects.annotate(avg_score=Avg(ArraySubquery(score_subquery)))

错误信息:

function avg(integer[]) does not exist

需求是仅通过注解实现,不使用存储字段。

可行方案

方案一:利用反向关联直接聚合

这是最简洁的实现方式,借助Django的反向关联(默认名为evaluation_set),直接在Employee的注解中计算平均值:

from django.db.models import Avg, F

employees_with_avg = Employee.objects.annotate(
    avg_score=Avg(F('evaluation__question1') + F('evaluation__question2'))
)

Django会自动生成正确的SQL,对每个员工的所有评估记录计算question1+question2的平均值,无需额外子查询。

方案二:子查询内完成聚合计算

如果需要处理更复杂的得分逻辑,可以在子查询中先算出单个员工的平均分,再关联到Employee:

from django.db.models import Avg, F, OuterRef, Subquery

# 子查询中先对当前员工的所有评估计算平均分
avg_subquery = Evaluation.objects.filter(employee_id=OuterRef('pk')).annotate(
    total_score=F('question1') + F('question2')
).aggregate(avg_score=Avg('total_score')).values('avg_score')

employees_with_avg = Employee.objects.annotate(avg_score=Subquery(avg_subquery))

这里的核心是用aggregate在子查询内直接得到单个平均值,确保子查询仅返回一行结果,避免了"多行返回"的错误。

原方案失败原因

  • 第一种普通子查询写法:子查询返回了该员工的所有评估得分(多行数据),但Avg作为聚合函数无法直接处理多行子查询的结果,因此触发错误。
  • 第二种ArraySubquery写法:PostgreSQL没有内置的数组平均值计算函数,无法直接对integer[]类型执行avg操作,所以报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:50:21