Django QuerySet 二值子查询

Phi*_*fer 5 django django-queryset

给定一个模型

class Entity(models.Model):
    identifier = models.IntegerField()
    created = models.IntegerField()
    content = models.IntegerField()

    class Meta:
        unique_together = (('identifier', 'created'))
Run Code Online (Sandbox Code Playgroud)

我想created在具有 common 的对象中查询最大的所有对象identifier

在 SQL 中,子查询中的窗口函数解决了这个问题:

SELECT identifier, content
  FROM entity
  WHERE (identifier, created)
    IN (SELECT identifier, max(created) OVER (PARTITION BY identifier)
          FROM entity);
Run Code Online (Sandbox Code Playgroud)

另见:http : //sqlfiddle.com/#!17/c541f/1/0

窗口函数和子查询在 Django 2.0 中都可用。但是,我还没有找到用多列表达子查询表达式的方法。

有没有办法将该 SQL 查询转换为 Django QuerySet 世界?这可能是一个 XY 问题,我的问题可以用不同的方式解决吗?

我丑陋的解决方法是

Entity.objects.raw('''
SELECT * FROM app_entity e
 WHERE e.created = (SELECT max(f.created) FROM app_entity f WHERE e.identifier = f.identifier)''')
Run Code Online (Sandbox Code Playgroud)

因为底层的 sqlite3 版本显然无法处理多列子查询。

Mat*_*kel 3

我认为你可以用另一种方式来做(但我不确定它是否会比窗口表达式表现更好或更差)...

max_created = Entity.objects.filter(
    identifier=OuterRef('identifier')
).order_by('-created').values('created')[:1]

Entity.objects.filter(
    created=Subquery(max_created)
)
Run Code Online (Sandbox Code Playgroud)

这会created获取给定 的最大值identifier作为相关子查询,然后仅过滤那些匹配的值。

这可能需要调整:我不确定您是否可以像这样过滤子查询,或者是否需要.annotate(max_created=Subquery(created)).filter(created=F('max_created')) 或其他类似的可怕事情。

另外,如果你使用的是 postgres,你可以使用该DISTINCT ON功能来获得一个非常简洁的解决方案:

Entity.objects.order_by('identifier', '-created').distinct('identifier')
Run Code Online (Sandbox Code Playgroud)