代码之家  ›  专栏  ›  技术社区  ›  HenryM

获取django查询集中所有字段的总和

  •  2
  • HenryM  · 技术社区  · 6 年前

    我正在尝试对查询集中的记录中的字段进行求和。我基本上想要每个领域的总和。

    我这样做如下:

    field_names = MyModel._meta.get_fields()
    queryset = MyModel.objects.filter(some filter criteria)
    
    for fn in field_names:
        result = queryset.aggregate(Sum(fn.name))
        actual = result[fn.name+'__sum']
    

    这显然是非常低效的。我如何有效地做到这一点?

    1 回复  |  直到 6 年前
        1
  •  4
  •   willeM_ Van Onsem    6 年前

    效率低下可能是由于您对每一列执行查询这一事实造成的。作为20个字段的结果,您将执行20个查询。

    查询的成本通常很高,而且很大一部分类型是“独立于查询”的,这意味着它需要时间,不管查询本身应该做什么:一个人需要创建查询,将其传递到数据库,然后数据库需要制定一个“查询执行计划”,然后执行查询,并与资源通信。小马回来了。当然,查询本身需要一些时间,正如您所看到的,还需要运行一些其他任务, 查询。因此,即使查询非常便宜,它们也会消耗大量资源。但是,如果过滤也是非常重要的(不是用索引可以很容易地解决的问题),那么我们还需要做大量的重复工作来确定要考虑表中的哪些行。

    你可以做这一切 首次使用聚合 列表理解 ,然后作为 *args :

    result = queryset.aggregate(*[Sum(fn.name) for fn in field_names])

    现在 result 是一个将所有这些字段映射到它们对应的和的字典,类似于:

    #  example result
    result == { 'foo__sum': 42, 'bar__sum': 14, 'qux__sum': 52 }
    

    因此,查询将如下所示:

    SELECT SUM(foo) AS foo__sum, SUM(bar) AS bar__sum, SUM(qux) AS qux__sum
    FROM mymodel
    WHERE 1 = 1  -- some filter conditions
    

    因此,所有集料的计算公式如下: 相同的 查询。

    注释 因为 field_names 是字段的集合,而不是字段的名称,我建议将此变量重命名为 fields 相反,为了避免以后的混乱。