向Django Admin添加图表
简介
Django为数据库后台管理提供了一个具有CRUD接口的开箱即用的功能性管理UI。这涵盖了基本内容和用户管理系统的大多数用例。然而,它没有提供显示摘要或历史趋势的探索性视图,而这正是你期望从管理仪表板中看到的。
幸运的是,django后台管理应用程序是可扩展的,通过一些调整,我们可以将交互式Javascript图表添加到后台管理中。
问题
我想获得findwork.dev上电子邮件订阅用户随时间变化的图表预览。就电子邮件用户而言,该网站是在增长还是停滞不前?上个月我们有多少订阅用户?哪个星期我们得到的订阅用户最多?所有用户都在验证他们的电子邮件吗?
通过使用图示,我们可以获得一个我们站点运行情况的历史概览。
我最初探索了现成的Django后台管理应用程序和仪表板。我们的要求是它包括图表化能力、良好的文档和好看的外观。虽然我试用的所有应用程序在样式方面看起来都比默认的后台管理要好,但它们要么缺少文档,要么就是没有得到维护。
- xadmin ——没有英文文档
- django-jet ——自从其核心团队开始开发一个SaaS替代项目后,它就再没有得到维护。
- django-grapinelli ——没有图形化功能
这时我脑袋中突然出现一个想法: 为什么不扩展默认的后台管理应用程序呢?
扩展 django-admin
Django后台管理应用程序由ModelAdmin类组成。这些表示后台管理界面中模型的可视视图。默认情况下,一个ModelAdmin类有5个默认视图:
- ChangeList ——一个模型集合的列表视图
- Add ——一个允许你添加一个新模型实例的视图
- Change ——一个更新模型实例的视图
- Delete ——个用于确认模型实例删除的视图
- History ——一个模型实例上执行的操作的历史
当你想要查看一个特定的模型时,ChangeList视图是默认的后台管理视图。我想在这里添加一个图表,以便我每次打开EmailSubscribers页面时,都能看到随时间变化添加的订阅者。
假设我们有这样一个电子邮件订阅者模型:
为了在后台管理应用程序中显示电子邮件订阅者,我们需要创建一个从django.contrib.admin.ModelAdmin扩展而来的类。
一个基本的ModelAdmin看起来是这样的:
我们来添加一些订阅者,这样我们就有了一个初始数据集:
如果我们进入ChangeList视图,我们将看到我们已经添加了100个新的订阅者,创建时间是随机的http://localhost:8000/admin/web/emailsubscriber/。
假设我们想添加一个图表,该图表在一个条形图中总结了随时间变化的订阅者数量。我们想把它放在订阅者列表的上方,这样你一进入网站就能看到它。
下面的红色区域描画出了我希望直观地放置图表的位置。
如果我们创建一个新文件,我们可以强制django-admin去加载我们的模板来代替默认模板。让我们在以下位置创建一个空文件:
- web/templates/admin/web/emailsubscriber/change_list.html.
重写管理模板时的命名方案是
- {{app}}/templates/admin/{{app}}/{{model}}/change_list.html.
默认的ChangeList视图是可扩展的,并且具有多个块,你可以覆盖这些块来满足你的需要。当我们检查默认的后台管理模板时,我们可以看到它包含可以被覆盖的块。我们需要覆盖content块来更改在模型表之前呈现的内容。
我们来扩展默认的ChangeList视图并添加自定义文本:
太棒了,我们现在成功地定制了后台管理UI。让我们更进一步,使用Chart .js来添加一个Javascript图表。我们需要覆盖extrahead块来添加脚本和样式元素进而在header中加载Chart.js。
Chart.js代码是基于在这里可以找到的演示条形图表。我稍微修改了一下它,以便在X轴上读取时间序列数据。
瞧,我们现在已经在django后台管理中呈现了一个Chart .js图表。唯一的问题是数据是硬编码的,而不是从后端派生的。
将图表数据注入后台管理模板
ModelAdmin类有一个名为changelist_view的方法。此方法负责呈现ChangeList页面。通过重写此方法,我们可以将图表数据注入模板上下文。
下面的代码大致是做这一任务的:
- 按每天的时间间隔聚合新的订阅用户的总数
- 将Django QuerySet编码为JSON
- 将数据添加到模板上下文
- 调用super()方法来呈现页面
从技术上来讲,数据现在应该已经被添加到模板上下文中了,但是现在我们必须在我们的图表中使用它来代替硬编码数据。
用来自我们后端的数据替换chartData变量中的硬编码数据:
重新加载页面来查看我们漂亮的图表。
使用JS动态加载数据
在上面的示例中,我们将初始图表数据直接注入html模板。在初始页面加载之后,我们可以进行更多的交互以及获取数据。为此,我们需要:
- 向我们的返回JSON数据的模型后台管理添加一个新的端点。
- 添加JS逻辑去对一个按钮单击执行AJAX调用以及重新呈现图标。
添加一个新端点需要我们去覆盖modeladmin上的get_urls()方法,并注入我们自己的端点url。
需要注意的是,你的自定义url应该在默认url之前进行访问。默认的url是宽容模式的,它们会匹配任何东西,所以请求永远不会经过我们的自定义方法。
我们的python代码现在应该是这样的:
我们还需要添加Javascript逻辑,以便在按钮单击时重新加载图表数据并重新呈现图表。在图表变量的声明下面添加以下行:
在图表的下面添加一个html按钮:
Chart.js提供了不同的开箱即用的可视化功能,使用基本图表是很容易的。它还提供了自定义功能,以备需要。它们的文档在这里。Django后台管理文档在这里。
Chart.js文档:https://www.chartjs.org/docs/latest/
Django后台管理文档:https://www.chartjs.org/docs/latest/
完整的示例代码可以在Github上找到。(https://github.com/danihodovic/django_admin_chart_js )
英文原文:https://findwork.dev/blog/integrating-chartjs-django-admin/
译者:野生大熊猫