Mur*_*nio 5 python django django-queryset django-aggregation
我知道如何GROUP BY汇总:
>>> from expenses.models import Expense
>>> from django.db.models import Sum
>>> qs = Expense.objects.order_by().values("is_fixed").annotate(is_fixed_total=Sum("price"))
>>> qs
<ExpenseQueryset [{'is_fixed': False, 'is_fixed_total': Decimal('1121.74000000000')}, {'is_fixed': True, 'is_fixed_total': Decimal('813.880000000000')}]>
Run Code Online (Sandbox Code Playgroud)
但是,如果我想对其他两列做同样的事情,它只返回最后一个:
>>> qs = (
... Expense.objects.order_by()
... .values("is_fixed")
... .annotate(is_fixed_total=Sum("price"))
... .values("source")
... .annotate(source_total=Sum("price"))
... .values("category")
... .annotate(category_total=Sum("price"))
... )
>>> qs
<ExpenseQueryset [{'category': 'FOOD', 'category_total': Decimal('33.9000000000000')}, {'category': 'GIFT', 'category_total': Decimal('628')}, {'category': 'HOUSE', 'category_total': Decimal('813.880000000000')}, {'category': 'OTHER', 'category_total': Decimal('307')}, {'category': 'RECREATION', 'category_total': Decimal('100')}, {'category': 'SUPERMARKET', 'category_total': Decimal('52.8400000000000')}]>
Run Code Online (Sandbox Code Playgroud)
可以只用一个查询而不是三个查询来完成我想要的吗?
预期结果:
<ExpenseQueryset [{'category': 'FOOD', 'total': Decimal('33.9000000000000')}, {... all other categories ...},
{'source': 'MONEY', 'total': Decimal('100')}, {... all other sources ...}, {'is_fixed': False, 'total': Decimal('1121.74000000000')}, {'is_fixed': True, 'total': Decimal('813.880000000000')}]>
Run Code Online (Sandbox Code Playgroud)
最理想的情况是,它可以拆分为以下内容:
<ExpenseQueryset ['categories': [{'category': 'FOOD', 'total': Decimal('33.9000000000000')}, {... all other categories ...}],
'sources': [{'source': 'MONEY', 'total': Decimal('100')}, {... all other sources ...}], 'type': [{'is_fixed': False, 'total': Decimal('1121.74000000000')}, {'is_fixed': True, 'total': Decimal('813.880000000000')}]]>
Run Code Online (Sandbox Code Playgroud)
但这只是一个很大的好处。
但是您可以使用以下方法结合 python 编码:
我认为即使在原始 SQL 中也是不可能的,因为在每个查询中您可以按一个或多个字段分组在一起,但不能为每个字段提供单独的结果。 但可以通过一个查询来完成此操作,并使用少量的 Python 代码以您想要的格式合并结果。下面我描述了如何逐步使用它。并在下一节中编写了一个 python 方法,您可以动态地将其用于任何进一步的用途。
我可以提到的唯一简单的解决方案是,按所需的 3 个字段进行分组,并进行简单的 Python 编程,将每个字段的结果相加。在此方法中,您将只有一个查询,但每个字段分组都有单独的结果。
from expenses.models import Expense
from django.db.models import Sum
qs = Expense.objects.order_by().values("is_fixed", "source", "category").annotate(total=Sum("price"))
Run Code Online (Sandbox Code Playgroud)
现在结果将如下所示:
<ExpenseQueryset [{'category': 'FOOD', 'is_fixed': False, 'source': 'MONEY', 'total': Decimal('33.9000000000000')}, { ...},
Run Code Online (Sandbox Code Playgroud)
现在我们可以通过迭代这个结果来简单地聚合每个字段结果
<ExpenseQueryset [{'category': 'FOOD', 'is_fixed': False, 'source': 'MONEY', 'total': Decimal('33.9000000000000')}, { ...},
Run Code Online (Sandbox Code Playgroud)
该字段的结果category将是这样的:
[{'category': 'FOOD', 'total': 33.3}, {... other category results ...}
Run Code Online (Sandbox Code Playgroud)
现在我们可以继续按字段为其他分组生成结果is_fixed,source如下所示:
category_keys = []
for q in qs:
if not q['category'] in category_keys:
category_keys.append(q['category'])
# Now we have proper values of category in category_keys
category_result = []
for c in category_keys:
value = sum(item['total'] for item in qs if item['category'] == c)
category_result.append({'category': c, 'total': value)
Run Code Online (Sandbox Code Playgroud)
现在我们知道如何使用这个解决方案,这里有一个函数,可以为您提供您想要的字段,并动态地为您提供正确的结果。
[{'category': 'FOOD', 'total': 33.3}, {... other category results ...}
Run Code Online (Sandbox Code Playgroud)
现在只需在您的代码中简单地使用它,如下所示:
source_keys = []
for q in qs:
if not q['source'] in source_keys:
source_keys.append(q['source'])
source_result = []
for c in source_keys:
value = sum(item['total'] for item in qs if item['source'] == c)
source_result.append({'source': c, 'total': value)
is_fixed_keys = []
for q in qs:
if not q['is_fixed'] in is_fixed_keys:
source_keys.append(q['is_fixed'])
is_fixed_result = []
for c in is_fixed_keys:
value = sum(item['total'] for item in qs if item['is_fixed'] == c)
is_fixed_result.append({'is_fixed': c, 'total': value)
Run Code Online (Sandbox Code Playgroud)
它会给出一个值列表,例如您想要的正确格式
| 归档时间: |
|
| 查看次数: |
197 次 |
| 最近记录: |