代码之家  ›  专栏  ›  技术社区  ›  Felipe Ferri

我可以对Django中以前的聚合函数的结果使用聚合函数吗?

  •  0
  • Felipe Ferri  · 技术社区  · 4 年前

    我在一个查询中收到以下错误:

    Cannot compute Sum('failures'): 'failures' is an aggregate
    

    我使用的是django1.11和python2.7。

    我有一个表示付款的模型:

    class Payment(models.Model):
        created = models.DateTimeField(null=True)
        customer_name = models.CharField(max_length=50)
        status = models.CharField(max_length=20) # e.g. 'paid' or 'failed'
    

    当用户进行购买并尝试使用其信用卡进行支付时,将创建一个支付对象。如果尝试失败,则状态变为“失败”。一个用户可以尝试多次,生成几个状态为“失败”的支付对象,然后放弃,或者当她尝试使用不同的卡时,第n次支付成功。

    我想执行一个聚合查询,在这个查询中,我可以同时计算失败尝试的总数和“唯一”失败的次数,也就是说,计算每个尝试失败的客户的一次失败。

    例如,假设我们有以下付款尝试

    Date/Time          Customer Name    Status
    2020-11-10 8:00a.m Alice            failed
    2020-11-10 8:01a.m Alice            failed
    2020-11-10 8:02a.m Alice            failed
    2020-11-10 8:10a.m Bob              failed
    2020-11-10 8:11a.m Bob              paid
    2020-11-11 7:30a.m Charles          failed
    2020-11-11 7:31a.m Charles          failed
    

    Date               Total failures   unique failures
    2020-11-10         4                2
    2020-11-11         2                1
    

    在第一天有3个失败的爱丽丝和1个鲍勃,所以总共有4个失败,但如果我们不考虑重复,只有2个独特的失败。第二天有两次失败,但只有一次是唯一的失败。

    因此,我做的第一件事是使用像这样的查询集按客户名称进行聚合:

    qs = Payment.objects
        .annotate(date=TruncDate('created'))
        .values('date', 'customer_name')
        .annotate(
            # Sum payments only if status == 'failed'
            failures=Sum(
                Case(
                    When(
                        status='failed',
                        then=1,
                    ),
                    default=0,
                    output_field=IntegerField()
                )
            ),
            # I could not think of a better way of doing this... Basically
            # for every payment that has status 'failed' I return the value
            # '1' and then calculate the average, which should be '1', for 
            # whatever number of failures.
            unique_failures=Avg(
                Case(
                    When(
                        status='failed',
                        then=1,
                    ),
                    default=0,
                    output_field=IntegerField()
                )
            )
        )
    

    此查询集运行良好,并返回:

    Date               Customer name    failures         unique failures
    2020-11-10         Alice            3                1.0
    2020-11-10         Bob              1                1.0
    2020-11-11         Charles          2                1.0
    

    qs.values('date', 'failures', 'unique_failures')
        .annotate(
            total_failures=Sum('failures'),
            total_unique_failures=Sum('unique_failures'),
        )
    

    但是,此操作失败,并出现错误:

    有没有一种方法可以对以前的聚合函数的结果执行聚合函数?如果没有,是否有另一种方法来计算每天唯一失败的次数?换句话说,至少有一次失败的客户数量是多少?

    0 回复  |  直到 4 年前