Django查询返回最多3个字段名称的总和最高

时间:2018-07-13 14:54:37

标签: python django django-models django-queryset

我的Django模型中有下表:

Date         | Field1 | Field2 | Field3 | Field4 | Field5 | Field6 |

05/01/2018   |      7 |      1 |      8 |      4 |      9 |      2 |
05/02/2018   |      9 |      2 |      1 |      1 |      6 |      2 |
05/03/2018   |      8 |      1 |      3 |      1 |      5 |      1 |
05/04/2018   |      7 |      1 |      8 |      4 |      9 |      2 |
05/05/2018   |      7 |      1 |      8 |      4 |      9 |      2 |

我想返回自定义时间段内具有最高总和的前3个字段的名称。

例如,如果我想获得前5个字段中的 NAMES ,这些字段在2018年5月2日至2018年5月4日之间的总和最高,则应返回以下内容:

“字段1,字段5,字段3”

因为:

Date         | Field1 | Field2 | Field3 | Field4 | Field5 | Field6 |

05/02/2018   |      9 |      2 |      1 |      1 |      6 |      2 |
05/03/2018   |      8 |      1 |      3 |      1 |      5 |      1 |
05/04/2018   |      7 |      1 |      8 |      4 |      9 |      2 |

SUM          |     24 |      4 |     12 |      6 |     20 |      5 |

我可以执行以下操作:

1)使用__dict__

返回字段名称列表(我的Django模型的类的属性)

2)遍历所有字段名称,通过过滤日期和使用.aggregate(SUM())汇总表中的值,并将结果放入{FieldNames:Sums}的字典中

3)最后,按值(总和)对字典进行排序,并提取与前3个值相对应的键(字段名称)。

这种方法似乎过于矫and过正,我想知道是否存在使用Querysets实现此目的的更Pythonic / Django风格的方法?

1 个答案:

答案 0 :(得分:0)

我相信条件聚合可以解决这个问题;您将汇总每个字段的总和,例如...

https://docs.djangoproject.com/en/2.0/ref/models/conditional-expressions/#case

from django.db.models import Case, When, IntegerField
from django.db.models.functions import Cast

uglyquery = ModelName.objects.aggregate(
     field_name_sum=Sum(
         Case(
             When(
                 Q(timestamp__lte=date.today() & Q(timestamp __gte=start_date)),
                 then=Cast('field_name',IntegerField()) # pretty sure the Cast is necessary
             ), output_field= IntegerField())
         )
     ),
     field_2_sum=....
 )

将返回一个包含所有字段和总和的字典,然后可以对其进行排序。

现在,因为我们无法使用python from operator import itemgetter对字典进行排序,所以我们有了...

How do I sort a dictionary by value?

sorted(uglyquery.items(), key=itemgetter(1))[3:6] 
# slice the first three results and leave only the remaining that we are interested in

告诉排序后的函数以每个字段的总和进行排序,此方法以元组列表(即[('Field2',4), ('Field6',5), ...]

)的升序返回字段

由于我们对最小值进行了切片,因此剩下的三个字段在该日期范围内的总和最高为6。 :)