Django orm 为每个组获取最新信息
Posted
技术标签:
【中文标题】Django orm 为每个组获取最新信息【英文标题】:Django orm get latest for each group 【发布时间】:2013-11-24 06:56:21 【问题描述】:我正在将 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 - Get the latest record for the group 所述 但它没有帮助。
【问题讨论】:
【参考方案1】:这是一个使用Greatest
和辅助annotate
的示例。我正面临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")
)
参考:
https://docs.djangoproject.com/en/3.1/ref/models/database-functions/#greatestfrom django.db.models import Max
【讨论】:
【参考方案2】:这应该适用于 Django 1.2+ 和 MySQL:
Score.objects.annotate(
max_date=Max('student__score__date')
).filter(
date=F('max_date')
)
【讨论】:
这需要很长时间才能运行! @emisilva 我不相信这种数据结构和数据库后端有更有效的方法。如果您需要它更快 - 添加索引或重构数据结构。 如果你有很多分数,这真的很慢。 仅作记录:此解决方案生成 N^2 行并过滤它们(N=Score count),如果 N 大于数千,则无用。最好做一个 O(N) 查询并找到每个学生的max_date
,然后发出另一个查询确实得到实际的Score
对象。或者如果您在 Postgres 上,请使用 @Rohan 的答案。【参考方案3】:
如果你的数据库是支持distinct()
的postgres,你可以试试
Score.objects.order_by('student__username', '-date').distinct('student__username')
【讨论】:
不幸的是我正在使用 mysql 您在尝试聚合此类查询时可能会遇到问题:NotImplementedError: aggregate() + distinct(fields) not implemented.
重要的是不要在这个查询集上调用.update()
之类的东西。从 1.11 开始,这将默默地做错事。
如果我在 order_by
前加上 filter_by
前缀,这是否也有效?
@NirIzr 是的,将过滤器放在order_by()
之前,它应该可以按预期工作。【参考方案4】:
我相信这会给你学生和数据
Score.objects.values('student').annotate(latest_date=Max('date'))
如果您想要完整的 Score
记录,您似乎必须使用原始 SQL 查询:Filtering Django Query by the Record with the Maximum Column Value
【讨论】:
以上是关于Django orm 为每个组获取最新信息的主要内容,如果未能解决你的问题,请参考以下文章
Django ORM group by,并找到每个组的最新项目(窗口函数)