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

Django中基于ManyToManyField关联表join后分组并取最新记录的方法

问题场景

你有两个存在多对多关联的Django模型,需要查询所有Education实例,以及每个实例关联的created_at最新的Price的cost值,每个Education仅返回一条结果。

原有查询问题说明

你当前使用的select_related('Price')是错误用法:select_related仅支持一对一、外键这类单值关联,多对多关联需要用prefetch_related;且原有查询会返回Education和关联Price的笛卡尔积,会出现同一个Education对应多条记录的情况,不符合需求。

实现方案

方案1:子查询实现(数据库层面过滤,性能更优)

直接在数据库层面完成最新Price的匹配,适合数据量较大的场景:

from django.db.models import OuterRef, Subquery

# 构造子查询:匹配当前Education关联的Price,按创建时间倒序取第一条的cost值
latest_price_subquery = Price.objects.filter(
    education=OuterRef('pk')
).order_by('-created_at').values('cost')[:1]

# 给每个Education实例注解最新的cost值
result = Education.objects.annotate(
    latest_cost=Subquery(latest_price_subquery)
).values_list('id', 'title', 'content', 'latest_cost')

如果需要获取完整的Education模型实例而非元组,去掉values_list直接遍历即可,每个实例会新增latest_cost属性存储最新的cost值。

方案2:Prefetch预取实现(内存层面过滤,适合关联数据量小的场景)

先预取所有关联的Price并按创建时间排序,之后在内存中取第一个值:

from django.db.models import Prefetch

# 预取关联的Price,按创建时间倒序排序,存入自定义属性sorted_prices
result = Education.objects.prefetch_related(
    Prefetch(
        'price', 
        queryset=Price.objects.order_by('-created_at'), 
        to_attr='sorted_prices'
    )
).all()

# 遍历获取每个Education的最新cost
for edu in result:
    latest_cost = edu.sorted_prices[0].cost if edu.sorted_prices else None
    # 后续业务逻辑

补充说明

如果你需要的是Education和Price关联的时间而非Price本身的创建时间,建议自定义多对多中间表,在中间表添加created_at字段,后续过滤基于中间表的时间字段即可,逻辑会更准确。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 11:54:07