【问题标题】:Django: filter by latest per distinct columnDjango:按每个不同列的最新过滤器
【发布时间】:2014-07-20 12:46:17
【问题描述】:

鉴于这个 FruitBasket 模型,

类水果篮(模型): 水果 = CharField(max_length=128) 计数 = PositiveIntegerField()

还有这个样本数据,

id水果计数 ----- ---------- ----- 0 苹果 10 1 根香蕉 20 2 苹果 5 3 香蕉 30

我想要一个返回以下项目的 django 查询:

[(2,苹果,5),(3,香蕉,30)]

基本上,抓取“最新”行 per 个水果(在此示例中,我已将时间戳简化为 rowid。)

【问题讨论】:

标签: python sql django distinct aggregate


【解决方案1】:

https://docs.djangoproject.com/en/dev/ref/models/querysets/#distinct

q = FruitBasket.objects.distinct('fruit')

仅当您使用 postgres 时才有效。

仅在 PostgreSQL 上,您可以在 为了指定 DISTINCT 应​​该到的字段的名称 申请。这将转换为 SELECT DISTINCT ON SQL 查询。这是 区别。对于普通的 distinct() 调用,数据库比较每个 在确定哪些行不同时,每行中的字段。为一个 distinct() 调用指定的字段名称,数据库将只 比较指定的字段名称。

此外,您必须指定 order_by 并且不能按时间戳:

q = FruitBasket.objects.distinct('fruit').order_by('fruit')

当您指定字段名称时,您必须在 QuerySet,并且 order_by() 中的字段必须以中的字段开头 distinct(),顺序相同。

例如,SELECT DISTINCT ON (a) 为您提供每个 a列中的值。如果你不指定订单,你会得到一些 任意行。

但是,如果您可以取消要求,values 可能会让您更接近:distinct/order_by 以相同的顺序具有相同的值。

q = (
    FruitBasket.objects
    .values('id', 'fruit', 'count')
    .distinct('fruit').order_by('-id')
)

实际上,有时候跳出 ORM 会更好

SELECT id, fruit, count 
FROM FruitBasket
GROUP BY fruit  
ORDER BY id DESC

所以这个查询并不神奇......

SELECT * FROM (SELECT id, fruit, count 
FROM FruitBasket
ORDER BY id DESC) t
GROUP BY t.fruit

这个更好,但有点丑。

自行优化:

q = FruitBasket.objects.raw("""\
    SELECT * FROM 
    (
        SELECT id, fruit, count 
        FROM FruitBasket 
        ORDER BY id DESC
    ) t
    GROUP BY t.fruit
""")

【讨论】:

  • 不确定你的意思是不是“q = FruitBasket.objects.values('id', 'fruit', 'count').distinct('fruit').order_by('-id' )" 应该可以工作,或者如果可以的话,它就是一个理想的选择。它没有。我可能只是重构以保留每个“水果”中“最新”条目的外键。 (实际上,“水果”是我现实世界问题中的外键。)
  • 我的意思是,如果它确实有效,那将是理想的,唯一有效的解决方案是底部的那个。顶部解释了为什么 orm 无法满足您的需求。
【解决方案2】:

你可以试试这个:

FruitBasket.objects.order_by('fruit', '-count').distinct('fruit')

就我而言,它适用于 Django 2.1

【讨论】:

  • 如文档和其他答案中所述,这仅适用于 PostgreSQL On PostgreSQL only, you can pass positional arguments (*fields) in order to specify the names of fields to which the DISTINCT should apply
【解决方案3】:

作为替代方案,如果您有固定(少量)可能的不同值,您可以使用多个查询(不是最佳的,但应该适用于小型项目):

available_fruits = ['banana', 'apple'] # can be also an extra query to extract distinct values
fruits = [FruitBasket.objects.filter(fruit=x).latest('id') for x in available_fruits ]

在我的情况下,它只有 4 个值,所以我可以进行 4 个简单快速的查询。

【讨论】:

    【解决方案4】:

    子查询可能会帮助您, 来自docs 的示例:

    >>> from django.db.models import OuterRef, Subquery
    >>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
    >>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))
    

    【讨论】:

      猜你喜欢
      • 2021-12-02
      • 2013-05-06
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 2021-03-25
      • 1970-01-01
      • 2021-03-10
      • 2016-07-26
      相关资源
      最近更新 更多