Django - 注释多个 Sum() 对象会给出错误的结果

Posted

技术标签:

【中文标题】Django - 注释多个 Sum() 对象会给出错误的结果【英文标题】:Django - Annotating multiple Sum() object gives wrong result 【发布时间】:2020-06-23 03:33:16 【问题描述】:

models.py 看起来像这样

class Channel(Model):
    name = CharField()

class Contract(Model):
    channel = ForeignKey(Channel, related_name='contracts')
    fee = IntegerField()

class ContractPayment(Model):
    contract = ForeignKey(Contract, related_name='payments')
    value = IntegerField()

当我查询模型时:

Channel.objects.annotate(pay=Sum('contracts__fee'))

返回:75000。它是正确的,但是当我这样查询时:

Channel.objects.annotate(pay=Sum('contracts__fee'))
               .annotate(paid=Sum('contracts__payments__value'))

它返回:支付:96000,支付:33000。如您所见,pay 已更改。这里发生了什么?我读了票#10060 但没有运气。

【问题讨论】:

Hopefull 在 Django 3.0 中为 Sum 添加了一个标志 distinct 我试过distinct,但Contract 模型有很多相同的费用,所以我不能在这里使用distinct 你看到***.com/questions/56567841/…了吗? 是的。那是不同的问题 可以接受两次查询吗? 【参考方案1】:

使用两个查询来获得想要的结果:

Channel.objects.annotate(pay=Sum('contracts__fee'))

Channel.objects.annotate(paid=Sum('contracts__payments__value'))

【讨论】:

如果我想区分 paypaid 怎么办。例如:qs.annotate(diff=F('pay') - F('paid'))【参考方案2】:

我认为您必须在annotate() 中使用distinct=True,如下所示...

Channel.objects.annotate(pay=Sum('contracts__fee', distinct=True)).annotate(paid=Sum('contracts__payments__value', distinct=True))

【讨论】:

你试试这个吗? 我试过了,因为ContractContractPayment 模型有很多相同的费用 你有解决方案还是还在寻找? 我通过不同的查询来实现这一点。但是这个问题还是可以接受的【参考方案3】:

如果您不使用 Django3,我认为这应该可以:

from django.db.models import Subquery, OuterRef, Sum
contracts = Contract.objects.filter(channel__id=OuterRef("id")).values("fee")
tot = contracts.values("channel_id").annotate(total=Sum("fee")).values("total")
Channel.objects.annotate(pay=Subquery(tot), paid=Sum('contracts__payments__value')).values()

【讨论】:

以上是关于Django - 注释多个 Sum() 对象会给出错误的结果的主要内容,如果未能解决你的问题,请参考以下文章

Django:根据字段的状态对 Sum Case 进行注释

Django ORM注释Sum计算错误及其乘以条目数,它是有线的

在 Django 查询集中编辑注释结果

注释总和的 Django 聚合平均值(1.6.5)

如何注释多个 django 模型

在 django orm 中对多个注释求和