我创建了一个查询集,它计算一个月和一年中的所有实例。 我希望它做的还包括计数为 0 的月份。即使我的数据库中没有月份的实例,我该怎么做?
payments_per_month = PaymentRequest.objects
.annotate(year=Extract('arrival_date', 'year')).values('year')
.annotate(month=Extract('arrival_date', 'month')).annotate(count=Count('*'))
.values('year', 'month', 'count').order_by('-year', '-month', 'count')
输出为:
<QuerySet [{'year': 2023, 'month': 3, 'count': 8}, {'year': 2023, 'month': 2, 'count': 5},
{'year': 2023, 'month': 1, 'count': 18}, {'year': 2022, 'month': 11, 'count': 2},
{'year': 2022, 'month': 10, 'count': 1}, {'year': 2022, 'month': 8, 'count': 1}]>
例如 December(12) 丢失,但我希望它在我的查询集中为:
{'year': 2022, 'month': 12, 'count': 0}
要在查询集中包含计数为零的月份,您可以首先生成要包含在查询集中的所有月份的列表。然后,你可以
annotate
这个月份列表的查询集,最后,你可以使用条件表达式来计算每个月的实例。
尝试以下操作:
from django.db.models import Case, When, Value, IntegerField
# Create a list of all the months
all_months = [
{'month': 1}, {'month': 2}, {'month': 3}, {'month': 4},
{'month': 5}, {'month': 6}, {'month': 7}, {'month': 8},
{'month': 9}, {'month': 10}, {'month': 11}, {'month': 12},
]
# Annotate the queryset with the list of all months.
payments_per_month = PaymentRequest.objects \
.annotate(year=Extract('arrival_date', 'year')) \
.annotate(month=Value(all_months, output_field=JSONField())) \
.values('year', 'month') \
.annotate(count=Count('*')) \
.order_by('-year', '-month')
# Use conditional expressions to count the instances of each month
payments_per_month = payments_per_month.annotate(
count=Case(
*[When(month__month=m['month'], then='count') for m in all_months],
default=Value(0),
output_field=IntegerField(),
),
)
# Extract the final queryset values
payments_per_month = payments_per_month.values('year', 'month__month', 'count').order_by('-year', '-month__month', 'count')
payments_per_month
的第一个实例存储初始查询集,该查询集统计当前和前几年每个月的实例,但不包括计数为零的月份。
payments_per_month
的第二个实例存储包含一年中所有月份的最终查询集,包括计数为零的月份。这个查询集是通过用所有月份的列表注释初始查询集,然后使用条件表达式来计算每个月的实例来生成的。
虽然
payments_per_month
的两个实例具有相同的名称,但它们在代码中的不同点引用不同的查询集。第一个实例被第二个实例覆盖,所以只有最终的查询集存储在代码末尾的payments_per_month
中。