【问题标题】:Django Aggregate- Division with Zero ValuesDjango 聚合 - 零值除法
【发布时间】:2017-01-15 09:21:03
【问题描述】:

我正在使用 Django 的 aggregate query expression 来汇总一些值。最终值是一个除法表达式,有时可能以零为分母。如果是这种情况,我需要一种方法来逃避,以便它简单地返回 0。

我尝试了以下方法,因为我一直在使用类似于我的注释表达式:

from django.db.models import Sum, F, FloatField, Case, When

def for_period(self, start_date, end_date):
    return self.model.objects.filter(
        date__range=(start_date, end_date)
    ).aggregate(
        sales=Sum(F("value")),
        purchase_cogs=Sum(F('purchase_cogs')),
        direct_cogs=Sum(F("direct_cogs")),
        profit=Sum(F('profit'))
    ).aggregate(
        margin=Case(
            When(sales=0, then=0),
            default=(Sum(F('profit')) / Sum(F('value')))*100
        )
    )

但是,它显然不起作用,因为正如错误所说:

'dict' 对象没有属性'aggregate'

处理这个问题的正确方法是什么?

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    这显然行不通;因为aggregate 返回的是字典,而不是QuerySet(参见docs),所以你不能将两个aggregate 调用链接在一起。

    我认为使用annotate 可以解决您的问题。 annotate 几乎与aggregate 相同,只是它返回一个 QuerySet,其结果保存为属性,而不是返回一个字典。结果是您可以链接annotate 调用,甚至调用annotate 然后aggregate。

    所以我相信类似的东西:

    return self.model.objects.filter(
        date__range=(start_date, end_date)
    ).annotate(  # call `annotate`
        sales=Sum(F("value")),
        purchase_cogs=Sum(F('purchase_cogs')),
        direct_cogs=Sum(F("direct_cogs")),
        profit=Sum(F('profit'))
    ).aggregate(  # then `aggregate`
        margin=Case(
            When(sales=0, then=0),
            default=(Sum(F('profit')) / Sum(F('value')))*100
        )
    )
    

    应该可以。

    希望这会有所帮助。

    【讨论】:

    • 正要回答,但你打败了我,并为此做出了更好的回答,所以 +1 给你 :)
    • 哈哈:D 谢谢!
    • 相同。很好的快速反应。
    • 这看起来应该可以工作,但由于 Django 的问题,现在还不行。我想我现在需要将它们放入两个操作中。 groups.google.com/forum/#!msg/django-updates/3YQKFNTmzrU/…
    • 我应该注意到我使用的是 Django 1.8,它很可能在最新版本中得到修复。
    【解决方案2】:

    我已经使它工作(在 Django 2.0 中):

    from django.db.models import Case, F, FloatField, Sum, When
    
    aggr_results = models.Result.objects.aggregate(
        at_total_units=Sum(F("total_units")),
        ag_pct_units_sold=Case(
            When(at_total_units=0, then=0),
            default=Sum("sold_units") / (1.0 * Sum("total_units")) * 100,
            output_field=FloatField(),
        ),
    )
    

    【讨论】:

      【解决方案3】:

      您不能将这样的聚合语句链接在一起。文档说:

      aggregate() 是 QuerySet 的终止子句,当被调用时, 返回名称-值对的字典。

      它返回一个python dict,所以你需要想办法修改你的查询,以便一次完成。您可能可以将第一个聚合调用替换为 annotate,因为它返回一个查询集:

      与aggregate() 不同,annotate() 不是终结子句。的输出 annotate() 子句是一个 QuerySet

      至于除以 0 的可能性,您可以将代码包装在 try catch 块中,注意 ZeroDivisionError。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-22
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-25
        • 2010-12-20
        • 2014-07-15
        相关资源
        最近更新 更多