You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Django QuerySet实现多列子查询获取最新Entity数据?

解决方案:Django中查询分组内最大值对应的对象

先看你的模型定义:

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

    class Meta:
        unique_together = (('identifier', 'created'))

你的需求是获取每个identifier分组中created值最大的对象,下面分几种情况来解决:

一、Django QuerySet实现(支持Django 2.0+)

虽然早期Django对多列IN子查询支持有限,但从Django 2.0开始,结合窗口函数或关联子查询可以实现需求,同时兼顾数据库兼容性:

方法1:窗口函数+过滤(需高版本SQLite)

我们可以用Window函数给每个对象标记其分组内的最大created值,再过滤出匹配的对象:

from django.db.models import Window, Max, F

# 给每个对象添加分组内的最大created值
annotated_entities = Entity.objects.annotate(
    max_created=Window(
        expression=Max('created'),
        partition_by=['identifier']
    )
)
# 筛选出created等于分组最大值的对象
result = annotated_entities.filter(created=F('max_created'))

注意:SQLite 3.25.0及以上才支持窗口函数,如果你的SQLite版本低于这个,这个写法会报错,这也是你之前遇到障碍的核心原因之一。

方法2:关联子查询(兼容低版本SQLite)

如果你的SQLite不支持窗口函数,用关联子查询可以实现和你临时Raw SQL完全一致的逻辑,同时用ORM写法避免硬编码:

from django.db.models import Subquery, OuterRef

# 子查询:获取当前identifier对应的最大created值
max_created_subquery = Entity.objects.filter(
    identifier=OuterRef('identifier')
).values('identifier').annotate(
    max_created=Max('created')
).values('max_created')

# 过滤出created等于子查询结果的对象
result = Entity.objects.filter(created=Subquery(max_created_subquery))

这个写法完全适配不支持窗口函数和多列子查询的SQLite版本,同时保留了ORM的可维护性。

二、关于XY问题的判断

你的问题不属于XY问题,核心需求非常明确:获取分组内最大值对应的完整对象,而非单纯的聚合统计值。不过如果你的场景只需要identifier和content字段,也可以先聚合再关联(得益于你的模型有unique_together约束,不会出现重复数据):

# 先获取每个identifier的最大created值
max_created_per_group = Entity.objects.values('identifier').annotate(
    max_created=Max('created')
)
# 关联原表获取对应内容
result = Entity.objects.filter(
    identifier__in=[item['identifier'] for item in max_created_per_group],
    created__in=[item['max_created'] for item in max_created_per_group]
)

三、临时Raw SQL方案的优化

你当前使用的Raw SQL是可行的,不过可以利用模型的元数据属性避免硬编码表名,提升代码可维护性:

table_name = Entity._meta.db_table
raw_query = f'''
    SELECT * FROM {table_name} e 
    WHERE e.created = (
        SELECT max(f.created) FROM {table_name} f 
        WHERE e.identifier = f.identifier
    )
'''
result = Entity.objects.raw(raw_query)

内容的提问来源于stack exchange,提问作者user1271598

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:24:07