Django:解包参数列表以用于聚合查询

2 投票
2 回答
1101 浏览
提问于 2025-04-15 19:31

我正在尝试创建一个半动态的聚合函数,这个函数会返回一个列表中所有字段的总和。假设运行 get_query_set() 会返回一个过滤后的查询,这个查询包含列表中的所有字段,还有一些可能不太适合用来做总和的字段(比如日期字段、字符字段、外键等...)

到目前为止,我想到的最佳示例如下,这主要是一个关于 Python 的问题,涉及到 Django 的特定用法,不过我的 Python 技能还不是很强...

有效的例子

qs = cl.get_query_set().aggregate(Sum('permits_submitted'), Sum('permits_pulled'), Sum('permits_posted'))

返回结果: {'permits_pulled__sum': 5772, 'permits_posted__sum': 6723, 'permits_submitted__sum': 7276}

无效的例子

qs = cl.get_query_set().aggregate(Sum('permits_submitted')).aggregate(Sum('permits_pulled'))

返回结果:错误

qs = cl.get_query_set().aggregate(Sum('permits_submitted', 'permits_pulled', Sum('permits_posted'))

返回结果:错误

无效的例子 - 展示了想法

tuple = (
        'permits_submitted',
        'permits_pulled',
        'permits_posted',
    )

qs = cl.get_query_set()
for field in tuple:
    qs.aggregate(Sum(field))

返回结果:错误

qs = cl.get_query_set()
qs.aggregate(*[Sum(field) for field in tuple])

返回结果:

[<permit_runner: User's report for 2010-02-18>, <permit_runner: User's report for 2010-02-19>, '...(remaining elements truncated)...'] 

(这和没有聚合的返回结果是一样的)

有效的例子

qs = cl.get_query_set()
qs = qs.aggregate(*[Sum(field) for field in tuple])

在添加聚合时错过了定义 qs =,休息几分钟再看会更清晰

2 个回答

0

创建动态聚合(或动态注释)

from typing import Dict
from django.db.models import Q, Sum


# 1. Prepare your querysets
years = year_allowances.values_list("year", flat=True)  
time_aways = TimeAway.objects.filter(  
    sequence__pk__in=sequences.values_list("pk", flat=True)  
).actual_paid_sick_leave()  

# 2. Define your individual aggregate expression.
def get_aggregate(key) -> Dict[str, Sum]:  
    return {  
        str(key): Sum(F('actual_paid_sick_leave'), filter=Q(local_timezone_start__year=key))  
    }  

# 3. Create the dictionary of aggregate expressions.
aggregate_expressions = {}  
ds = [{**get_aggregate(year)} for year in years]  
for d in ds:  
    aggregate_expressions.update(d)

# 4. Create your aggregations.
x = time_aways.aggregate(**aggregate_expressions)
>> x = {'2021': datetime.timedelta(0), '2022': datetime.timedelta(days=5)}
4

自从我完成这项工作后,我把它作为一个答案放在这里,这样大家在谷歌搜索的时候就能更容易找到它:

qs = cl.get_query_set()
qs = qs.aggregate(*[Sum(field) for field in tuple])

撰写回答