You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django QuerySet中按年月分组并包含0计数的月份

补全Django QuerySet中缺失月份的统计数据

要实现包含无数据月份(count为0)的统计,Django ORM无法直接生成空行,需要手动生成时间范围内的所有年月组合,再与现有统计结果合并。以下是具体实现步骤:

1. 确定统计的时间边界

首先获取数据库中PaymentRequest记录的最早和最晚arrival_date对应的年月,以此确定需要覆盖的时间范围:

from datetime import datetime
from django.db.models import Min, Max, Extract, Count

# 获取时间边界
date_bounds = PaymentRequest.objects.aggregate(
    min_year=Min(Extract('arrival_date', 'year')),
    min_month=Min(Extract('arrival_date', 'month')),
    max_year=Max(Extract('arrival_date', 'year')),
    max_month=Max(Extract('arrival_date', 'month'))
)

# 处理无数据的情况,默认取最近一年
if not all(date_bounds.values()):
    now = datetime.now()
    min_year, min_month = now.year - 1, now.month
    max_year, max_month = now.year, now.month
else:
    min_year, min_month = date_bounds['min_year'], date_bounds['min_month']
    max_year, max_month = date_bounds['max_year'], date_bounds['max_month']

2. 生成时间范围内的所有年月组合

遍历从起始年月到结束年月的所有月份,生成完整的年月列表:

all_months = []
current_year, current_month = min_year, min_month

while (current_year, current_month) <= (max_year, max_month):
    all_months.append({'year': current_year, 'month': current_month})
    # 月份递增,处理跨年逻辑
    if current_month == 12:
        current_year += 1
        current_month = 1
    else:
        current_month += 1

3. 获取原统计结果并转换为字典

将原QuerySet的统计结果转换为以(year, month)为键的字典,方便快速查找:

# 执行原统计查询
original_stats = PaymentRequest.objects.annotate(
    year=Extract('arrival_date', 'year'),
    month=Extract('arrival_date', 'month')
).values('year', 'month').annotate(count=Count('*'))

# 转换为字典,便于匹配
stats_map = {(item['year'], item['month']): item['count'] for item in original_stats}

4. 合并结果并补全缺失月份

遍历所有年月组合,匹配统计数据,缺失的月份设count=0,最后按需求排序:

full_stats = []
for month in all_months:
    key = (month['year'], month['month'])
    full_stats.append({
        'year': month['year'],
        'month': month['month'],
        'count': stats_map.get(key, 0)
    })

# 按年份降序、月份降序排序
full_stats.sort(key=lambda x: (-x['year'], -x['month']))

最终full_stats就是包含所有月份的统计结果,缺失的月份会显示count=0,比如你提到的2022年12月会被补全为{'year': 2022, 'month': 12, 'count': 0}。

内容的提问来源于stack exchange,提问作者haduki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:52:57