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

Flask传JSON渲染Chart.js饼图时报too many values to unpack错误

问题排查结果

当前报错和渲染失败是后端逻辑错误+前端API调用错误共同导致的,分点说明:

后端ValueError: too many values to unpack根因

  • 编写的聚合查询每行返回2个值:收支金额总和、对应的收支类型,循环时写for total_amount, in income_vs_expenses: 带了尾逗号,试图把每行结果解包为1个变量,和实际返回的字段数不匹配,直接触发解包错误。
  • 就算解包语法修正,写的total.amount也会报错:查询返回的行是元组,不是对象,不存在amount属性。
  • 提前用json.dumps序列化数据后,前端又调用Jinja2的tojson过滤器,会造成二次转义,JSON格式损坏,前端解析直接失败。

前端饼图渲染失败根因

  • Chart初始化的第一个参数要求传入canvas DOM对象或者2D渲染上下文,传了未定义的变量income_vs_expenses,找不到渲染目标。
  • 变量名混用:解析后的数据存在income_expenses变量里,配置里传参时变量名写错,且硬编码的labels顺序和数据库分组顺序可能不匹配,就算渲染成功也会出现数据和标签错位。
  • 页面如果没有提前写对应id的canvas元素,也会导致渲染失败。
修复方案

修正后的后端路由代码

@add_dash.route('/chart')
def chart():
    # 查询结果格式: [(金额总和, 收支类型), ...]
    db_result = db.session.query(
        db.func.sum(IncomeExpenses.amount),
        IncomeExpenses.type
    ).group_by(IncomeExpenses.type).order_by(IncomeExpenses.type).all()

    amount_data = []
    type_labels = []
    # 正确解包每行两个字段
    for total, i_type in db_result:
        amount_data.append(float(total)) # 转float避免Decimal类型序列化异常
        type_labels.append(i_type)

    # 直接传原生Python列表到模板,不要手动提前json.dumps
    return render_template(
        "chart.html",
        user=current_user,
        amount_data=amount_data,
        type_labels=type_labels
    )

修正后的前端JS代码

先确认模板里提前写了canvas元素:

<canvas id="incomeExpenseChart" width="400" height="400"></canvas>

然后替换JS部分:

{% block javascript %}
<script> 
    // tojson过滤器会直接输出合法JS数组,不需要额外JSON.parse
    const chartAmounts = {{ amount_data|tojson }};
    const chartLabels = {{ type_labels|tojson }};
    
    // 获取canvas上下文作为Chart初始化的第一个参数
    const ctx = document.getElementById('incomeExpenseChart').getContext('2d');
    
    new Chart(ctx, {
        type: 'pie',
        data: {
            labels: chartLabels, // 用后端返回的动态标签,避免硬编码错位
            datasets: [{
                label: "Income Vs Expenses",
                data: chartAmounts,
                backgroundColor: ['#5DA5DA', '#FAA43A', '#60BD68', '#B276B2', '#E16851', '#FB8267'],
                borderWidth: 1,
                hoverBorderColor: "black",
                hoverBorderWidth: 2,
                hoverBackgroundColor: 'rgba(154, 245, 140)',
                pointHoverRadius: 5
            }],
        },
        options: {
            title: {
                display: true,
                text: "Income Vs Expenses",
                fontSize: 20,
            },
            legend: {
                position: "right",
                labels: {
                    fontColor: "blue"
                },
                display: true,
            },
            elements: {
                hitRadius: 3,
            }
        }
    })
</script>
{% endblock %}
避坑提示
  • 数据库聚合返回的金额如果是Decimal类型,必须转成int/float再传给模板,否则JSON序列化会抛出类型不匹配错误。
  • Jinja2的tojson过滤器本身就会完成JSON序列化和XSS转义,不需要提前在后端做json.dumps,否则会出现双层转义的格式问题。
  • 不要硬编码图表标签,直接用查询返回的分组字段生成标签,避免分组顺序变化导致数据和标签对应错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:21:28