Django Admin 默认不支持图表,因其设计目标是快速生成基于HTML表格的基础管理界面,未内置图表库或渲染能力。需通过TemplateResponse自定义首页,安全注入JSON数据并用Chart.js渲染,避免修改ModelAdmin模板导致维护困难。

为什么 Django Admin 默认不支持图表?
Django Admin 的设计目标是快速生成数据管理界面,它只提供基础的列表、筛选、搜索和表单功能,所有渲染逻辑都基于 HTML 表格和模板变量。它没有内置图表渲染能力,也不加载 Chart.js 或 Plotly 这类前端库。想加图表,本质是「在 Admin 页面里嵌入自定义 HTML + JS」,而不是调用某个现成的 add_chart() 方法。
这意味着你必须手动控制三件事:数据如何从后端传到前端、前端如何请求或接收数据、图表库如何初始化和渲染。绕过这点,直接搜“Django Admin chart plugin”容易踩进维护性差或兼容性崩坏的第三方包坑里。
最简可行方案:用 TemplateResponse 替换默认首页
Django Admin 首页(/admin/)本质上是一个视图,你可以用自定义视图完全接管它,同时复用 Admin 的权限、导航栏和 CSS 主题。
操作步骤:
立即学习“Python免费学习笔记(深入)”;
- 在
admin.py或独立视图文件中定义一个函数视图,用TemplateResponse返回自定义模板 - 在
urls.py中把admin.site.urls前插入你的新首页路由(顺序很重要) - 模板继承
admin/base_site.html,确保左侧菜单、顶部栏正常显示 - 在模板里用
json_script标签安全注入统计结果(避免 XSS),再用Chart.js渲染
示例关键代码:
# views.py
from django.template.response import TemplateResponse
from django.contrib.admin.views.decorators import staff_member_required
<p>@staff_member_required
def admin_dashboard(request):</p><h1>示例:统计最近 7 天订单数</h1><pre class='brush:python;toolbar:false;'>from datetime import timedelta
from django.utils import timezone
from myapp.models import Order
data = Order.objects.filter(
created_at__gte=timezone.now() - timedelta(days=7)
).extra({'day': "date(created_at)"}) \
.values('day') \
.annotate(count=models.Count('id')) \
.order_by('day')
context = {'chart_data': list(data)}
return TemplateResponse(request, 'admin/dashboard.html', context)如何安全传递数据给前端图表?
不能直接用 {{ chart_data|json_script }} 然后在 JS 里 JSON.parse() —— 因为 Admin 模板里已有多个 json_script(比如 changelist 的 filters),ID 冲突会导致 JS 报错 TypeError: Cannot read property 'textContent' of null。
正确做法是给每个 json_script 指定唯一 id:
{{ chart_data|json_script:"dashboard-order-data" }}
<script>
const data = JSON.parse(document.getElementById('dashboard-order-data').textContent);
// 初始化 Chart.js
</script>
注意点:
- 后端聚合结果必须是纯 Python list/dict,不能含
datetime对象(会 JSON 序列化失败),需用strftime('%Y-%m-%d')转字符串 - 如果图表需实时刷新,别用长轮询;改用
fetch()调用单独的 API endpoint(如/admin/api/order-stats/),并确保该 endpoint 加了@staff_member_required - 避免在模板里写复杂 JS 逻辑——把图表初始化封装成独立函数,放在
static/admin/js/dashboard.js中引入
为什么不要重写 ModelAdmin 的 change_list_template?
有人试图通过覆盖某个 ModelAdmin 的 change_list_template 来加图表,这只能在特定模型列表页生效,且无法复用 Admin 的全局导航结构。更严重的是:当你在 OrderAdmin 里加了销售额折线图,用户点击左侧「Users」菜单时,图表就消失了——因为那是另一个 UserAdmin 的模板,彼此隔离。
仪表盘的核心诉求是「统一入口、全局可见」,不是「每个模型页塞一个图表」。强行拆到各个 ModelAdmin,后期维护成本指数级上升,权限控制也变复杂(比如某图表要跨 3 个模型查数据,就得在 3 个地方重复写权限逻辑)。
真正需要关注的是:数据聚合的性能边界(比如千万级订单表的每日统计要不要走物化视图)、图表库版本与 Admin 当前 jQuery 版本的兼容性(Chart.js v4+ 已弃用 jQuery 依赖,但老项目可能还混着用)、以及是否把敏感统计指标暴露给了所有 staff 用户——这些比“怎么画出第一个柱状图”重要得多。


















