同时使用两个注释表达式时出现错误结果

2024-09-25 06:30:58 发布

您现在位置:Python中文网/ 问答频道 /正文

假设下表:

class Table1(models.Model): 
    Column1 = models.IntegerField()
class Table2(models.Model):  
    Column2 = models.IntegerField()
class Table3(models.Model):  
    Table1 = models.ForeignKey(Table1, null=False, on_delete=models.CASCADE)
    Table2 = models.ForeignKey(Table2, null=False, on_delete=models.CASCADE)
    Column3 = models.IntegerField()
class Table4(models.Model):  
    Table1 = models.ForeignKey(Table1, null=False, on_delete=models.CASCADE)
    Table3 = models.ForeignKey(Table3, null=False, on_delete=models.CASCADE)
    Column4 = models.IntegerField()

此注释表达式返回正确答案:

^{pr2}$

即:

<QuerySet [{'Exp1': 96}]>

我需要定义另一个注释表达式,如下所示:

print(Table1.objects.annotate(Exp2=Sum(
            Case(
                When(table4__Table3__Table2__Column2=3,
                     then=F('table4__Column4')),
                default=Value(0)
            ),
      )).values('Exp2'))

结果再次正确:

<QuerySet [{'Exp2': 0}]>

最后,我想把这两个命令结合起来:

print(Table1.objects.annotate(Exp1=Sum(
            Case(
                When(table3__Table2__Column2__in=[2, 3],
                     then=F('table3__Column3')),
                default=Value(0)
            ),
    ), Exp2=Sum(
            Case(
                When(table4__Table3__Table2__Column2=3,
                     then=F('table4__Column4')),
                default=Value(0)
            ),
    )).values('Exp1', 'Exp2'))

但不幸的是,结果并不正确:

<QuerySet [{'Exp2': 0, 'Exp1': 480}]>

Tags: falsemodelonmodelsdeletenullclasscascade
2条回答

报告了这个bug here,但即使在django1.11中也没有解决。这个问题与连接反向关系中的两个表有关。 请注意,distinct参数对Count有效,但对Sum无效。所以我用了一个技巧,写了下面的ORM,效果很好:

print(Table1.objects.annotate(
    temp_Exp1=Sum(
            Case(
                When(table3__Table2__Column2__in=[2, 3],
                     then=F('table3__Column3')),
                default=Value(0)
            ),), 
    temp_Exp2=Sum(
            Case(
                When(table4__Table3__Table2__Column2=3,
                     then=F('table4__Column4')),
                default=Value(0)
            ),),
    table3_count=Count('table3'),
    table3_count_distinct=Count('table3', distinct=True),
    table4_count=Count('table4'),
    table4_count_distinct=Count('table4', distinct=True),
).annotate(
    Exp1=F('temp_Exp1')*F('table3_count_distinct')/F('table3_count'),
    Exp2=F('temp_Exp2')*F('table4_count_distinct')/F('table4_count'),
).values('Exp1', 'Exp2'))

使用带有annotate的多个聚合时有一个警告:

Combining multiple aggregations with annotate() will yield the wrong results because joins are used instead of subqueries. For most aggregates, there is no way to avoid this problem...

而且,与Count的聚合不同,Sum不采用可以帮助重复数据消除的distinct参数。如果你想得到正确的结果,我想你应该保留不同的查询。在

Combining multiple aggregations。在

相关问题 更多 >