通过最大列值过滤Django查询记录

11

有没有一种简单的方法可以根据某一列中的最大/最小值筛选Django查询结果?我实际上是在特定上下文中询问此类问题,即Django的ORM,和 这些 问题 是类似的。

例如:

假设我有一个模型用于存储每个人电话号码的历史记录。

class Person(models.Model):
    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=100)
    created = models.DateTimeField(auto_now_add=True)

使用这些记录:

Person(name='Jim',phone='123-456-9870', created=datetime(2005,1,2,4,2))
Person(name='Jim',phone='329-802-9870', created=datetime(2006,9,2,7,8))
Person(name='Sue',phone='324-345-3450', created=datetime(2008,7,4,6,1))

现在假设我想找到每个人最近的电话号码。

在SQL中,通常需要使用子查询来计算最大值:

SELECT p1.name, p1.phone, p1.created
FROM person_person p1, (
    SELECT name, MAX(created) AS max_created
    FROM person_person
    GROUP BY name
) AS p2
WHERE p1.name = p2.name AND p1.created = p2.max_created
有没有Django的机制可以简化这个过程?
我正在使用PostgreSQL,所以任何依赖于PostgreSQL特定功能的想法或解决方案都将很有帮助。

似乎在Django中,除非使用原始查询SQL,否则无法实现您要查找的内容。请参阅此链接。由于在添加order_by('created')时,创建的内容会被添加到查询中的select语句中,因此distinct将不起作用。 - Hassek
你可以使用Django ORM来实现,参见我的回答:https://dev59.com/lWw05IYBdhLWcg3wy052#65898703 - trecouvr
3个回答

5

在这里,您可能只想使用原始的SQL查询,raw() 管理器方法可以实现这一点,允许您从查询中返回模型实例。唯一的问题是原始查询需要包括主键。以下代码应该适用于您(除非您将主键设置为其他内容而不是 id):

latest_phone_numbers = Person.objects.raw('''
SELECT p1.id, p1.name, p1.phone, p1.created
FROM person_person p1, (
    SELECT name, MAX(created) AS max_created
    FROM person_person
    GROUP BY name
) AS p2
WHERE p1.name = p2.name AND p1.created = p2.max_created
''')

3

更新:如果您使用的是PostgreSQL,可以使用ORM和.distinct()。

来自PostgreSQL文档

SELECT DISTINCT ON ( expression [, ...] )仅保留给定表达式评估为相等的每组行集中的第一行。DISTINCT ON表达式使用与ORDER BY相同的规则进行解释(见上文)。请注意,每个集合的“第一行”除非使用ORDER BY确保所需行首先出现,否则是不可预测的。

使用Django ORM:


Person.objects.order_by('name', '-created').distinct('name')


生成的SQL:
select distinct on (name)
    ...
from person_person
order by name, created desc

1
如果您的后端是PostgreSQL,Roman Pekar提供了一个很好的答案this问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接