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

Chart.js与Django 3:费用数据月份标签匹配异常问题求助

问题分析与解决方案

这问题我之前也碰到过,核心是你的数据顺序和Chart.js的月份标签顺序没有对应,另外代码里还有个小bug会导致费用统计不准确,我帮你一步步梳理:

问题根源

  1. 数据与标签不匹配:你当前的total_earn_month、total_etp_month、total_ep_month都是只包含有数据的月份的字典,直接取values()得到的是仅存在数据的月份值,而你的labels是固定的12个月份顺序。当只有8月的数据时,values()返回的列表只有一个元素,Chart.js会自动把它匹配到第一个标签(January)上,这就是为什么显示成1月数据。
  2. 待支付费用统计bug:在统计待支付费用的循环里,你写的是total_etp_month[etp_month] = expense.price,不管是否已经存在该月份的键,都直接赋值而不是累加,这会导致同一个月份的多个待支付费用只会保留最后一个的价格,而不是总和。

修复步骤

我们需要确保每个月份(1-12)都有对应的数据(没有数据的月份填0),这样数据的顺序就能和labels的12个月份完全对应:

1. 初始化全月份的统计字典

把原来的空字典初始化改为包含1-12月、初始值为0的字典,这样每个月份都有初始值,后续只需要累加即可:

# 按月份统计总营收(初始化1-12月为0)
total_earn_month = {month: 0 for month in range(1, 13)}
for invoice in invoices:
    invoice_month = invoice.created_at.month
    total_earn_month[invoice_month] += invoice.total

# 按月份统计待支付总费用(修复累加bug+初始化全月份)
total_etp_month = {month: 0 for month in range(1, 13)}
for expense in expenses_to_pay:
    etp_month = expense.invoice_date.month
    total_etp_month[etp_month] += expense.price  # 这里改成+=,修复累加bug

# 按月份统计已支付总费用(初始化全月份)
total_ep_month = {month: 0 for month in range(1, 13)}
for expense in expenses_paid:
    ep_month = expense.purchase_date.month
    total_ep_month[ep_month] += expense.price

2. 计算总费用时保持全月份顺序

现在因为total_etp_month和total_ep_month都是包含1-12月的字典,直接按月份顺序相加即可,不需要用集合取键:

total_expenses = {month: total_ep_month[month] + total_etp_month[month] for month in range(1, 13)}

3. 返回数据时保持顺序

现在total_earn_month.values()和total_expenses.values()都是按1-12月的顺序返回的,和你的labels顺序完全匹配,转成列表可以确保顺序稳定:

return Response({
    'labels': labels,
    'sales': list(total_earn_month.values()),
    'total_expenses': list(total_expenses.values())
})

完整修改后的视图代码

class SalesExpensesChart(APIView):
    """
    视图:列出所有营收与费用
    * 需要会话认证(SessionAuthentication)
    * 仅认证用户可查看自身数据
    """
    authentication_classes = [SessionAuthentication]
    permission_classes = []

    def get(self, request, format=None):
        user = Account.objects.get(email=request.user)
        invoices = user.invoice.all()
        expenses_to_pay = user.expenses_to_pay.all()
        expenses_paid = user.expenses_paid.all()

        # 按月份统计总营收(初始化1-12月为0)
        total_earn_month = {month: 0 for month in range(1, 13)}
        for invoice in invoices:
            invoice_month = invoice.created_at.month
            total_earn_month[invoice_month] += invoice.total

        # 按月份统计待支付总费用(修复累加bug+初始化全月份)
        total_etp_month = {month: 0 for month in range(1, 13)}
        for expense in expenses_to_pay:
            etp_month = expense.invoice_date.month
            total_etp_month[etp_month] += expense.price

        # 按月份统计已支付总费用(初始化全月份)
        total_ep_month = {month: 0 for month in range(1, 13)}
        for expense in expenses_paid:
            ep_month = expense.purchase_date.month
            total_ep_month[ep_month] += expense.price

        # 按月份合并总费用(保持1-12月顺序)
        total_expenses = {month: total_ep_month[month] + total_etp_month[month] for month in range(1, 13)}

        # 获取标签
        labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

        # 打包数据传递至模板(转成列表确保顺序)
        sales = list(total_earn_month.values())
        total_expenses_data = list(total_expenses.values())

        return Response({
            'labels': labels,
            'sales': sales,
            'total_expenses': total_expenses_data
        })

这样修改后,8月的数据就会准确对应到labels里的August位置,不会再跑到January去,同时也修复了待支付费用的累加问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:38:11