如何用Django ORM实现多表关联查询与聚合操作?
Django ORM 实现多层关联模型的聚合查询需求
模型定义
以下是嵌套关联的Django模型结构(实际层级可能更多或更少):
class ModelA(models.Model): value = models.IntegerField() class ModelB(models.Model): modelA = models.ForeignKey(ModelA, on_delete=models.CASCADE) value = models.IntegerField() class ModelC(models.Model): modelB = models.ForeignKey(ModelB, on_delete=models.CASCADE) value = models.IntegerField() class ModelD(models.Model): modelC = models.ForeignKey(ModelC, on_delete=models.CASCADE) value = models.IntegerField() class ModelE(models.Model): modelD = models.ForeignKey(ModelD, on_delete=models.CASCADE) value = models.IntegerField() # 更多层级...
基础查询示例
1. 查询指定ModelA对应的所有ModelE
SQL等价语句:
SELECT ModelE.* FROM ModelA JOIN ModelB ON ModelB.modelA = ModelA.id JOIN ModelC ON ModelC.modelB = ModelB.id JOIN ModelD ON ModelD.modelC = ModelC.id JOIN ModelE ON ModelE.modelD = ModelD.id WHERE ModelA.id = 1
Django ORM实现:
ModelE.objects.filter(modelD__modelC__modelB__modelA_id=1)
2. 按ModelC分组并聚合ModelE的value
SQL等价语句:
SELECT ModelC.*, SUM(ModelE.value) FROM ModelA JOIN ModelB ON ModelB.modelA = ModelA.id JOIN ModelC ON ModelC.modelB = ModelB.id JOIN ModelD ON ModelD.modelC = ModelC.id JOIN ModelE ON ModelE.modelD = ModelD.id WHERE ModelA.id = 1 GROUP BY ModelC.id
Django ORM实现:
from django.db.models import Sum ModelC.objects.filter( modelB__modelA_id=1 ).annotate( sum_e_value=Sum('modelD__modelE__value') ).values('id', 'value', 'sum_e_value')
具体需求:计算ModelC.value与ModelE.value总和的乘积
用户需要实现等价于以下SQL的高效查询,替代低效的Python workaround:
SQL等价语句:
SELECT ModelC.value * SUM(ModelE.value) FROM ModelA JOIN ModelB ON ModelB.modelA = ModelA.id JOIN ModelC ON ModelC.modelB = ModelB.id JOIN ModelD ON ModelD.modelC = ModelC.id WHERE ModelA.id = 1 AND ModelD.value >= 1 AND ModelD.value < 3 GROUP BY ModelC.id
高效Django ORM实现
利用Django的F()表达式和聚合函数,直接在数据库层面完成计算,避免Python内存中处理数据:
from django.db.models import Sum, F result = ModelC.objects.filter( modelB__modelA_id=1, modelD__value__gte=1, modelD__value__lt=3 ).annotate( sum_e_value=Sum('modelD__modelE__value') ).annotate( calculated_result=F('value') * F('sum_e_value') ).values('id', 'calculated_result')
说明
- 使用
F()表达式直接引用数据库字段进行运算,所有计算逻辑在数据库端完成,避免了将大量数据加载到Python内存后再处理,大幅提升效率。 - 通过双层
annotate,先聚合得到sum_e_value,再基于该聚合值和ModelC.value计算最终结果。 filter中的多层关联查询modelB__modelA_id和modelD__value__gte/lt,对应SQL中的JOIN和WHERE条件。
内容的提问来源于stack exchange,提问作者IbbyStack
相关产品推荐
相关产品推荐

