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
相关产品推荐
相关产品推荐

