Django对接Chart.js绘制时序折线图时nan未定义报错求解
NumPy生成的np.nan调用.tolist()转为Python原生列表后,元素为Python标准库的float('nan')类型。Django模板直接渲染该值时会输出小写的nan,但JavaScript环境中不存在名为nan的全局变量,同时Chart.js仅识别null作为折线空值断点,不识别JavaScript原生大写NaN,因此触发Uncaught ReferenceError报错。
优先在后端完成格式转换,从根源避免非法JS语法输出。
不要在前端用正则替换、字符串匹配等方式处理渲染后的
nan字符串,这类方案容错率低,一旦数据中存在包含"nan"的文本内容会出现误替换,稳定性差。
方案1:视图层直接替换NaN为None(最简便,适配现有模板逻辑)
Python的None值被Django模板渲染时会自动输出为JavaScript合法的null,完全符合Chart.js的空值识别规则。
在视图函数中生成orig_val、preds列表后,加一层列表推导转换即可:
import math # 转换历史值序列 orig_val = [None if isinstance(x, float) and math.isnan(x) else x for x in orig_val] # 转换预测值序列 preds = [None if isinstance(x, float) and math.isnan(x) else x for x in preds]
如果你的数据还没转成原生列表,仍是NumPy数组,可以用NumPy内置方法批量处理:
import numpy as np orig_val = np.where(np.isnan(orig_np_arr), None, orig_np_arr).tolist() preds = np.where(np.isnan(pred_np_arr), None, pred_np_arr).tolist()
转换完成后再把变量传给模板,现有模板里的{{ orig_val|safe }}、{{ preds|safe }}写法不需要改动,渲染后空值位置会自动输出null,Chart.js可正常识别。
- 如果你希望空值位置折线直接断开形成断点,把两个dataset配置里的
spanGaps设为false即可 - 如果希望空值前后的点自动连线,保留
spanGaps: true即可
方案2:用Django内置json_script标签传值(更安全规范)
直接用|safe渲染JS变量存在XSS注入风险,Django官方推荐用json_script模板标签传递数据给前端,该标签会自动处理特殊值转义,也会将非法NaN值转为兼容的null格式。
模板中写法调整为:
<!-- 先把数据渲染为安全的JSON脚本块 --> {{ new_dates|json_script:"chart-labels" }} {{ orig_val|json_script:"chart-hist-data" }} {{ preds|json_script:"chart-pred-data" }} <script> // 读取解析数据 const labels = JSON.parse(document.getElementById('chart-labels').textContent); const histData = JSON.parse(document.getElementById('chart-hist-data').textContent); const predData = JSON.parse(document.getElementById('chart-pred-data').textContent); // 初始化图表 new Chart(document.getElementById("chart"), { type: 'line', data: { labels: labels, datasets: [ { data: histData, label: "Historical Sales", borderColor: "#3e95cd", fill: false, spanGaps: false }, { data: predData, label: "Predictions", borderColor: "#22DD66", fill: false, spanGaps: false } ] }, options: { title: { display: true, text: 'output chart' }, maintainAspectRatio: false, responsive: true, scales: { xAxes: [{ gridLines: { display:false } }], yAxes: [{ gridLines: { display:false } }] }, animation: { duration: 2000, }, } }); </script>
这种写法不需要提前在视图层手动替换NaN,模板标签会自动完成合法JSON转换,同时避免XSS风险,适合生产环境使用。
内容的提问来源于stack exchange,提问作者logisticregress

