Django和Aggregate:不同值的总和?

时间:2010-12-06 22:25:01

标签: django django-orm

我正在尝试执行django聚合函数,但无法产生所需的结果。

我得到了什么:

income_posts.values_list('category__name','amount')
[(u'Donation', Decimal("2000.00")), (u'Paycheck', Decimal("1200.00")), (u'Donation', Decimal("1000.00"))]

期望的结果:

[(u'Donation', Decimal("3000.00")), (u'Paycheck', Decimal("1200.00))]

我需要汇总具有相同category__name的'amount'字段。

8 个答案:

答案 0 :(得分:17)

来自this answer for a related question

from django.db.models import Sum
income_posts.values('category__name').order_by('category__name').annotate(total=Sum('amount'))

答案 1 :(得分:4)

只需添加到arjun27的答案中即可。由于该软件包似乎已被放弃,您可能只想复制其中需要的3行:

from django.db.models import Sum
class DistinctSum(Sum):
    function = "SUM"
    template = "%(function)s(DISTINCT %(expressions)s)"

可以与上面相同地使用:

income_posts.annotate(total=DistinctSum('amount')

答案 2 :(得分:3)

如果您使用的是Postgres,则可以使用django-pg-utils package作为不同值的总和。

from pg_utils import DistinctSum
income_posts.annotate(total=DistinctSum('amount')

答案 3 :(得分:1)

对于那些使用django 2.2 LTE的用户,只需复制为Sum实现不同的django 3.0 commit,就可以实现此行为:

https://github.com/django/django/commit/5f24e7158e1d5a7e40fa0ae270639f6a171bb18e

这种方式:

from django.db.models Sum

class SumDistinctHACK(Sum):
    allow_distinct = True

现在您可以使用django 3.0语法:

queryset.annotate(
    sum_result=SumDistinctHACK(
        'relatedmodel__values_to_sum',
        distinct=True,
    )
)

如果升级到SumDistinctHACK,请记住将Sum替换为django >= 3.0

答案 4 :(得分:1)

对于旧版本的 Django,请使用 Func

queryset.annotate(
   sum_result=Sum(
        Func(F('amount'), function='DISTINCT')
   )
)

答案 5 :(得分:0)

Django 3.0在Sum和Avg上引入了“ distinct = True”: https://docs.djangoproject.com/en/3.0/ref/models/querysets/#sum

答案 6 :(得分:0)

你可以这样做:

income_posts.values("category__name").distinct().annotate(total=Sum("amount"))

答案 7 :(得分:0)

我认为这个问题也与Combining multiple aggregations有关。

Here is the ticket 此错误。

我们可以使用 Subquery(Django Docs) 来解决这个问题:

from django.db.models import Subquery, OuterRef, IntegerField, Sum, Value, Count

MyModel.objects.annotate(
    count_model_a=Count('ModelA', distinct=True), 
    sum_model_b=Coalesce(
        Subquery(
            ModelB.objects.filter(
                MyModel=OuterRef('pk')
            ).values('MyModel_id').annotate(
                my_sum=Sum('MyModel_Field')
            ).values('my_sum')[:1],
            output_field=IntegerField()
        ),
        Value(0)
    )
).values("count_model_a", "sum_model_b")

我还使用了 Coalesce(Django Docs) 函数来防止返回 None

以上代码将对数据库运行一次查询。