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

Django如何annotate关联外键集合求和 避免N+1查询问题

Django 关联集合条件求和优化方案

核心实现思路

通过Django ORM自带的条件聚合注解能力,将两次按支付类型过滤求和的逻辑直接嵌入SQL查询,一次性完成所有ReportCommissionPosition条目的字段注解,全程仅执行1次SQL,彻底解决N+1性能问题。

具体实现代码

首先导入依赖的ORM工具类:

from django.db.models import Sum, Case, When, DecimalField
# 如果需要无数据时默认返回0,额外导入Coalesce
from django.db.models.functions import Coalesce

然后直接对ReportCommissionPosition查询集做注解:

# 从report对象反向查询所有关联的position并注解目标字段
commission_positions = report.reportcommissionposition_set.annotate(
    trans_amount=Sum(
        Case(
            When(reservation__payment__payment_accounting_type='SELL', then='reservation__payment__amount'),
            output_field=DecimalField()
        )
    ),
    sum_amount=Sum(
        Case(
            When(reservation__payment__payment_accounting_type='TRANS', then='reservation__payment__amount'),
            output_field=DecimalField()
        )
    )
)

如果需要无对应支付记录时默认返回0而非None,调整注解写法即可:

trans_amount=Coalesce(
    Sum(
        Case(
            When(reservation__payment__payment_accounting_type='SELL', then='reservation__payment__amount'),
            output_field=DecimalField()
        )
    ),
    0,
    output_field=DecimalField()
)

注意事项

  • 代码中payment_accounting_type的匹配值需要和模型PAYMENT_TYPES中定义的数据库存储值保持一致,若你需求中提到的TRANSFER是实际存储值,把对应When条件中的TRANS替换为TRANSFER即可。
  • 注解完成后直接通过position.trans_amount、position.sum_amount就可以访问计算结果,不需要额外查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 14:39:02