Django orm 为每个组得到最新的

我使用的是 Django 1.6和 Mysql。

我有这些模型:

class Student(models.Model):
username = models.CharField(max_length=200, unique = True)


class Score(models.Model):
student = models.ForeignKey(Student)
date = models.DateTimeField()
score = models.IntegerField()

我想要得到每个学生的最新成绩记录。
我试过了:

Score.objects.values('student').annotate(latest_date=Max('date'))

以及:

Score.objects.values('student__username').annotate(latest_date=Max('date'))

Django ORM-获取该组的最新记录 但这并没有帮助。

32218 次浏览

我相信这会给你学生和数据

Score.objects.values('student').annotate(latest_date=Max('date'))

如果希望获得完整的 Score记录,似乎必须使用原始 SQL 查询: 使用最大列值的记录筛选 Django 查询

如果你的数据库是支持现场 distinct()的 postgres,你可以尝试

Score.objects.order_by('student__username', '-date').distinct('student__username')

这应该可以在 Django 1.2 + 和 MySQL 上运行:

Score.objects.annotate(
max_date=Max('student__score__date')
).filter(
date=F('max_date')
)

下面是一个使用 Greatest和辅助 annotate的示例。我当时面临的问题是,注释返回了重复的记录(示例) ,但是 last_message_time Greatest 注释导致了重复。

qs = (
Example.objects.filter(
Q(xyz=xyz)
)
.exclude(
Q(zzz=zzz)
)
# this annotation causes duplicate Examples in the qs
# and distinct doesn't work, as expected
# .distinct('id')
.annotate(
last_message_time=Greatest(
"comments__created",
"files__owner_files__created",
)
)
# so this second annotation selects the Max value of the various Greatest
.annotate(
last_message_time=Max(
"last_message_time"
)
)
.order_by("-last_message_time")
)


参考文献:

已经有一些很棒的答案,但是没有一个提到 窗户函数。

下面的示例用相应学生的最新分数注释所有分数对象:

from django.db.models import F, Window
from django.db.models.functions import FirstValue


scores = Score.objects.annotate(
latest_score=Window(
expression=FirstValue('score'),
partition_by=['student'],
order_by=F('date').desc(),
)
)

这导致以下 SQL (使用 Sqlite 后端) :

SELECT
"score"."id",
"score"."student_id",
"score"."date",
"score"."score",
FIRST_VALUE("score"."score")
OVER (PARTITION BY "score"."student_id" ORDER BY "score"."date" DESC)
AS "latest_score"
FROM "score"

所需的信息已经存在,但是我们还可以将这个查询集减少到一组 student_idlatest_score的惟一组合。

例如,在 PostgreSQL 上我们可以使用 与字段名不同,就像在 scores.distinct('student')中一样。

在其他数据库后端,我们可以执行类似于 set(scores.values_list('student_id', 'latest_score'))的操作,尽管这会计算查询集。

不幸的是,在编写本文时,过滤窗口查询集的是 还不可能