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

如何基于Django的AppealForm模型查询数据适配ChartJS折线图?

Django按自然月统计AppealForm关联Appeal数量(含空月份补0)

核心思路

要适配ChartJS的折线图需求,需要确保12个自然月的数据完整性——即使某月份没有关联的Appeal记录,也要返回0值。实现分两步:先生成全年12个月的基准框架,再将实际统计数据填充到框架中,空缺月份自动补0。

假设模型关系(需根据实际字段调整)

先明确模型关联逻辑(如果你的字段名不同,后续代码对应修改即可):

  • Appeal 模型通过外键(比如appeal_form)关联到 AppealForm
  • Appeal 包含时间字段(比如created_at)用于按月份统计
  • AppealForm 包含标识字段(比如name)用于区分不同表单

具体实现代码

1. 导入依赖模块

from django.db.models import Count
from django.db.models.functions import TruncMonth
from datetime import datetime

2. 生成全年12个月的基准数据

先构建一个包含当年所有月份的基础结构,确保不会缺失任何月份:

# 可替换为指定年份,比如target_year = 2024
current_year = datetime.now().year
# 生成格式为"YYYY-MM-01"的月份基准列表
month_baseline = [
    {"month_str": f"{current_year}-{month:02d}-01"} 
    for month in range(1, 13)
]

3. 执行分组统计查询

通过TruncMonth按月份截断时间字段,结合Count统计每个AppealForm各月份的关联Appeal数量:

# 统计当前年份内,每个AppealForm各月份的Appeal数量
appeal_monthly_stats = AppealForm.objects.annotate(
    # 截断Appeal的创建时间到月份,注意替换为实际字段路径
    month=TruncMonth('appeal__created_at')
).values('id', 'name', 'month').annotate(
    appeal_count=Count('appeal')
).filter(
    month__year=current_year
).order_by('id', 'month')

4. 补全空月份数据

将查询结果与基准月份合并,空缺月份自动填充0:

# 整理为每个AppealForm对应完整12个月的统计结果
form_monthly_data = {}
for stat in appeal_monthly_stats:
    form_id = stat['id']
    form_name = stat['name']
    # 将日期对象转为基准列表的字符串格式
    stat_month_str = stat['month'].strftime('%Y-%m-%d')
    count = stat['appeal_count']

    if form_id not in form_monthly_data:
        # 初始化该表单的12个月数据,默认值为0
        form_monthly_data[form_id] = {
            'form_id': form_id,
            'form_name': form_name,
            'counts': {mb['month_str']: 0 for mb in month_baseline}
        }
    # 填充有数据的月份
    form_monthly_data[form_id]['counts'][stat_month_str] = count

# 转换为列表格式,方便传递给前端
final_result = list(form_monthly_data.values())

5. 适配ChartJS数据格式

将处理后的数据转换为ChartJS所需的标签+数据数组结构:

# 生成x轴的月份标签(比如"Jan", "Feb")
month_labels = [
    datetime.strptime(mb['month_str'], '%Y-%m-%d').strftime('%b') 
    for mb in month_baseline
]

# 生成折线图的数据集
chart_datasets = []
for form_data in final_result:
    chart_datasets.append({
        'label': form_data['form_name'],
        'data': list(form_data['counts'].values()),
        'borderColor': f'#{hash(form_data["form_name"]) % 0xFFFFFF:06x}',  # 动态生成唯一颜色
        'fill': False,
        'tension': 0.1
    })

额外调整说明

  • 若需区分written/oral类型的Appeal,可在查询时添加过滤条件:.filter(appeal__type='written'),分别统计两类数据后合并到ChartJS的数据集。
  • 如果模型的外键字段名或时间字段名不同,比如Appeal关联AppealForm的外键是form,时间字段是submitted_at,则修改TruncMonth('form__submitted_at')即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:47:30