使用 Django ORM 注释查询以计算 2 个表值的总和
Posted
技术标签:
【中文标题】使用 Django ORM 注释查询以计算 2 个表值的总和【英文标题】:Annotate query for calculate sum of 2 table value with Django ORM 【发布时间】:2019-03-26 14:23:58 【问题描述】:我有两张桌子
Class Billing(models.Model):
id=models.AutoField(primary_key=True)
.....
#Some more fields
....
Class BillInfo(models.Model):
id=models.AutoField(primary_key=True)
billing=models.ForeignKey(Billing)
testId=models.ForeignKey(AllTests)
costOfTest=models.IntegerField(default=0)
concession=models.IntegerField(default=0)
这里BillInfo
是垂直表,即一个Billing
有多个BillInfo
。在这里,我想计算单个Billing
的Sum(costOfTest - concession)
。
我可以使用单个查询来实现吗?
需要帮助,提前致谢。
【问题讨论】:
从BillInfo
到Billing
的ForeignKey
是什么?
是的,问题已更新。
【参考方案1】:
你可以这样写:
from django.db.models import F, Sum
Billing.objects.annotate(
the_sum=Sum(F('billinfo__costOfTest') - F('billinfo__concession'))
)
这里QuerySet
中的每个Billing
对象都将有一个额外的属性.the_sum
,它是所有costOfTest
s 减去所有相关BillingInfo
的concession
的总和对象。
计算此值的 SQL 查询大致如下:
SELECT billing.*
SUM(billinginfo.costOfTest - billinginfo.concession) AS the_sum
FROM billing
LEFT OUTER JOIN billinginfo ON billinginfo.billing_id = billing.id
GROUP BY billing.id
因此,当您“实现”查询时,查询将在一次调用中获得所有Billing
对象的总和。
对于没有任何相关BillingInfo
的Billing
对象,the_sum
属性将为None
,我们可以通过使用Coalesce
[Django-doc]函数来避免这种情况:
from django.db.models import F, Sum, Value
from django.db.models.functions import Coalesce
Billing.objects.annotate(
the_sum=Coalesce(
Sum(F('billinfo__costOfTest') - F('billinfo__concession')),
Value(0)
)
)
【讨论】:
BillingInfo
具有 Billing
作为 ForeignKey
。收到错误django.core.exceptions.FieldError: Cannot resolve keyword 'billinfo' into field.
@GAJESHPANIGRAHI:确实,正如您在查询中看到的那样,我们在 JOIN
中使用了此外键的 billing_id
对应项。
@GAJESHPANIGRAHI:关键是如果你从模型A
到B
定义一个ForeignKey
,Django 会构造一个从B
引用的隐式 关系到A
。
但我想从Billing
模型访问BillInfo
,而Billing
是BillInfo
的ForeignKey。有一个对象billinginfo_set
。
@GAJESHPANIGRAHI:我们正在从Billing
访问BillingInfo
。注意F('billinginfo__...')
。 ForeignKey
位于其他位置的事实不 很重要,因为数据库会生成JOIN
,并且通常会有适当的索引来正确执行此操作。并不是因为数据库中没有explicitForeignKey
,所以获取relatedBillingInfo
的集合是个问题。以上是关于使用 Django ORM 注释查询以计算 2 个表值的总和的主要内容,如果未能解决你的问题,请参考以下文章
Django ORM distinct 查询,其中订单由带注释的字段完成,您需要 distinct('id')