簡體   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