繁体   English   中英

Django:在可变的列数上注释总和

[英]Django: Annotate sum on variable number of columns

所以,我读过的注释列,并利用F()函数,我看到这个帖子就如何总结多列。 但是,我正在使用EAV样式数据库,因此为我提供了可变的列列表。 考虑示例:

class TestModel(models.Model):
    column_a = models.FloatField()
    column_b = models.FloatField()
    column_c = models.FloatField()
    column_d = models.FloatField()

尝试1:

columns = {'column_a', 'column_c', 'column_d'}
queryset = DummyModel.objects.annotate(total=Sum([F(column_name) for column_name in columns]))

但是, print(queryset.query)产生错误django.core.exceptions.FieldError: Cannot resolve expression type, unknown output_field

尝试2:

queryset = DummyModel.objects.annotate(total=ExpressionWrapper(Sum([F(column_name) for column_name in columns]), output_field=FloatField())) 

这不会产生编译错误,但是SQL查询会产生:

SELECT "test_model"."column_a", "test_model"."column_c", "test_model"."column_d", SUM([]) AS "total" FROM "test_model"

哪个是空的。 有谁知道如何解决这个问题? 任何帮助是极大的赞赏!

为了弄清楚这一点,它有助于首先绘制表格:

column_a | column b | column_c
---------+----------+----------
1        | 2        | 3
4        | 5        | 6
7        | 8        | 9

Sum是“垂直”运算; 也就是说,如果我们想要column_a的总和,我们可以做

>>> DummyModel.objects.aggregate(total=Sum('column_a'))
{'total': 12}

如您所见,这将返回1 + 4 + 7 == 12因此您可以看到为什么我称其为“垂直”总和。 注意,我们使用aggregate而不是annotateaggregate用于垂直运算符。

相反,如果我们想要“水平”总和-行的总和-我们将使用F()+ 因此,要在每一行中获取column_a + column_b ,我们将使用

>>> DummyModel.objects.annotate(total=F('column_a') + F('column_b')).values('total')
<QuerySet [{'total': 3}, {'total': 9}, {'total': 15}]>

希望您能明白为什么我称其为“水平”总和:我们在每一行中得到的ab “水平”总和。 现在注意我们使用annotate ,它用于水平操作。

如果事先不知道各列的名称,则需要花一些技巧并使用functools.reduceoperator.add来构建一个表达式:

>>> from functools import reduce
>>> from operator import add

>>> cols = ['column_b', 'column_c']
>>> expr = reduce(add, (F(col) for col in cols))
>>> DummyModel.objects.annotate(total=expr).values('total')
<QuerySet [{'total': 5}, {'total': 11}, {'total': 17}]>

如果我们要同时使用水平和垂直总和-即总和column_a加总和column_b -我们需要用SumF()

>>> DummyModel.objects.aggregate(total=Sum(F('column_a') + F('column_b')))
{'total': 27}

注意: aggregate而不是注释,因为我们最终要进行垂直操作; Sum 是的,首先要进行水平操作,但是由于我们最终Sum ,所以需要aggregate

因此,要总结一下,如果字段是一个变量,则需要从上面组合aggregateSumreduce技巧:

>>> cols = ['column_b', 'column_c']
>>> expr = reduce(add, (F(col) for col in cols))
>>> DummyModel.objects.aggregate(total=Sum(expr))
{'total': 33}

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM