Django中如何将template变量传递给views 点击链接生成对应图表
可落地方案(适配你用的template/views分层架构,默认是Django技术栈)
整个流程完全匹配你说的交互逻辑,分三个环节实现就行,没有复杂依赖:
1. Template层:链接携带绘图参数
最省事的方式是用GET参数传值,不用提前给每个图表写单独路由,后续加新图表只要改链接参数就行。
- 最简写法:直接给a标签拼参数,指向后端图表接口,配合页面上的图表容器:
<!-- 页面上放几个图表跳转链接 --> <a class="chart-link" href="/chart/generate/?chart_type=bar&metric=sales&dim=month">月度销量柱状图</a> <a class="chart-link" href="/chart/generate/?chart_type=bar&metric=user_count&dim=city">城市用户数柱状图</a> <!-- 图表渲染容器 --> <div id="chart-container"></div>
- 不想点链接跳走的话,加十几行原生JS做异步请求,点完直接把图表插到容器里,体验更好:
document.querySelectorAll('.chart-link').forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); fetch(this.href) .then(res => res.text()) .then(chartContent => { document.getElementById('chart-container').innerHTML = chartContent; }) }) })
如果连JS都不想写,直接把带参的接口地址当img的src属性,打开页面就能直接出图,点链接跳转到单独的图片页也能用。
2. Views层:接收参数生成图表
先在urls.py里把接口路由配上:
from django.urls import path from . import views urlpatterns = [ path('chart/generate/', views.generate_chart, name='generate_chart'), ]
视图函数里两种实现方案二选一就行:
方案A:后端用matplotlib生成图片(适合静态柱状图场景)
逻辑很简单:接参数→做白名单校验→查数据→绘图→转成流返回,不要存本地临时文件,省得后续清理。
from django.http import HttpResponse import matplotlib.pyplot as plt import pandas as pd import io import base64 # 提前配置matplotlib中文显示,避免中文乱码 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False def generate_chart(request): # 提取前端传的绘图参数 chart_type = request.GET.get('chart_type', '') metric = request.GET.get('metric', '') dim = request.GET.get('dim', '') # 必须做参数白名单校验,别直接把前端传的值丢进查询/绘图逻辑,避免报错和注入风险 ALLOWED_CHART = ['bar'] ALLOWED_METRIC = ['sales', 'user_count'] ALLOWED_DIM = ['month', 'city'] if chart_type not in ALLOWED_CHART or metric not in ALLOWED_METRIC or dim not in ALLOWED_DIM: return HttpResponse("参数不合法", status=400) # 替换成你自己的业务数据查询逻辑,根据传入的dim、metric拉对应数据 # 这里用测试数据举例 source_data = pd.DataFrame({ 'month': ['1月', '2月', '3月', '4月'], 'sales': [120, 210, 180, 250], 'city': ['北京', '上海', '广州', '深圳'], 'user_count': [300, 420, 280, 350] }) # 绘制柱状图 fig, ax = plt.subplots(figsize=(8, 4)) ax.bar(source_data[dim], source_data[metric]) ax.set_title(f'{dim}维度{metric}统计柱状图') # 把图转成base64格式返回,不用写本地文件 buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight') plt.close(fig) # 必须关图,不然请求多了会内存泄漏 buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode() # 异步请求返回带img标签的片段,直接插入页面就行 return HttpResponse(f'<img src="data:image/png;base64,{img_base64}" style="max-width: 100%;">')
方案B:返回ECharts配置(适合需要图表交互的场景)
如果需要鼠标悬浮看数值、切换维度这类交互,就别在后端生成图片,后端只查数据、拼ECharts需要的配置,返回给前端渲染,性能更好:
- 视图里查完数据,组装成ECharts要求的option结构,用JsonResponse返回
- 前端拿到配置后,直接调用ECharts实例的
setOption方法渲染就行,比后端生成图片负载低很多
3. 实用避坑点
- 参数校验必须做,别嫌麻烦,不然用户随便改URL传个不存在的字段,接口直接500报错
- matplotlib绘图一定要记得调用
plt.close(fig)释放内存,线上跑久了内存会爆 - 相同参数的图表可以加个5-10分钟的缓存,不用每次请求都重新查数绘图,能省很多服务器资源
- 如果要导出图表,直接在绘图逻辑里加个下载标识参数,返回的时候加响应头就能触发浏览器下载,不用额外写接口
内容的提问来源于stack exchange,提问作者Ant_Esc
相关产品推荐
相关产品推荐

