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

Django查询父模型时如何注解子模型关联字段聚合值

Django多表继承下跨子模型条件聚合方案

问题明确答复

  1. 完全可以通过父模型查询注解子模型的关联数据。你使用的是Django默认的多表继承模式,父类Order和每个子类之间会自动创建一对一关联,关联名默认为子类名的全小写形式:Order到BorrowOrder的关联为borroworder,到ReturnOrder的关联为returnorder。查询父类时ORM会自动通过LEFT JOIN关联子类表,支持通过双下划线语法跨子类、子类的关联表取字段。
  2. 可以通过Case+When实现条件选择聚合字段,注意处理NULL值即可。

可直接使用的实现代码

基础写法(适合子类数量少、数据量不大的场景)

from django.db.models import Sum, Case, When, Value, Coalesce

qs = Order.objects.annotate(
    total_qty=Sum(
        Case(
            # 匹配借阅单类型,取借阅中间表的数量字段
            When(
                borroworder__isnull=False,
                then=Coalesce('borroworder__borrowed_parts__qty_borrowed', Value(0))
            ),
            # 匹配归还单类型,取归还中间表的数量字段
            When(
                returnorder__isnull=False,
                then=Coalesce('returnorder__returned_parts__qty_returned', Value(0))
            ),
            # 其他类型订单默认数量为0
            default=Value(0)
        )
    )
)

写法说明

  • 用borroworder__isnull=False判断当前订单属于BorrowOrder子类,这是Django多表继承下判断子类类型的标准ORM写法,无需额外加字段。
  • Coalesce的作用是将关联不存在时产生的NULL值转为0,避免Sum聚合时因NULL值导致结果异常。
  • 字段路径遵循ORM双下划线规则:父模型 -> 子类一对一关联 -> 中间表反向关联(即你在中间表外键定义的related_name) -> 数量字段。
  • 后续新增订单子类时,只需要在Case中追加对应的When分支即可。

高性能写法(适合数据量大、子类多的场景)

基础写法会通过LEFT JOIN关联所有子类表、子类对应的中间表,数据量大时可能有性能损耗,可改用子查询聚合避免多表连接:

from django.db.models import Sum, Case, When, Value, Coalesce, Subquery, OuterRef

# 构建借阅单数量聚合子查询
borrow_total = BorrowOrderPart.objects.filter(
    borrow_order_id=OuterRef('pk')
).values('borrow_order_id').annotate(
    total=Sum('qty_borrowed')
).values('total')[:1]

# 构建归还单数量聚合子查询
return_total = ReturnOrderPart.objects.filter(
    return_order_id=OuterRef('pk')
).values('return_order_id').annotate(
    total=Sum('qty_returned')
).values('total')[:1]

qs = Order.objects.annotate(
    total_qty=Coalesce(
        Case(
            When(borroworder__isnull=False, then=Subquery(borrow_total)),
            When(returnorder__isnull=False, then=Subquery(return_total)),
            default=Value(0)
        ),
        Value(0)
    )
)

这种写法每个子查询单独聚合对应中间表的数量,不会产生多表连接的重复行问题,数据量越大性能优势越明显。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 19:09:52