【问题标题】:Django Query to Return Max 3 Field Names With Highest SumDjango 查询返回最多 3 个总和最高的字段名称
【发布时间】:2018-07-13 14:54:36
【问题描述】:

我的 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 个字段的名称。

例如,如果我想获取 05/02/2018 和 05/04/2018 之间总和最高的前 3 个字段的 NAMES,则应返回以下内容:

'Field1, Field5, Field3'

因为:

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) 最后按值(Sums)对字典进行排序,提取前 3 个值对应的键(Field Names)。

这种方式似乎有点过头了,我想知道是否有更 Pythonic/Django 风格的方式来使用 Querysets 来实现这一点?

【问题讨论】:

  • 我认为将其存储在不同的字段中是不好的设计。在这种情况下,unpivot 数据可能会更好。列的概念实际上是那些 正交 数据元素,因此一列通常(或非常有限)与另一列交互。
  • @WillemVanOnsem 谢谢你的意见,我同意你的看法,很遗憾我在这里处理遗留代码,手头工作的要求之一是保持数据库格式不变在任何情况下都不要改变它。我只需要解决当前的数据库格式。

标签: python django django-models django-queryset


【解决方案1】:

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

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

告诉 sorted 函数按照我们对每个字段的总和进行排序,该方法将字段按升序返回为元组列表,即[('Field2',4), ('Field6',5), ...]

因为我们对最低值进行了切片,所以我们只剩下该日期范围内 6 个总和最高的三个字段。 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-27
    • 2022-10-15
    • 1970-01-01
    • 2022-07-26
    • 2016-08-25
    • 2016-08-27
    • 2016-04-27
    • 1970-01-01
    相关资源
    最近更新 更多