(五)前端表单交互
(六)Ajax异步传参与加载
(七)前端数据格式的处理
(八)DataTables接管前端表格
(九)Pyecharts实现交互图表
(十)静态图表的展示
(十一)“导出数据至Excel”功能
(十二)添加和配置缓存
(十三)用户登录系统
(十四)部署Django至生产环境
在上一章,我们已经成功从后端将分析结果传回前端Django模板并展示,但这个分析结果是静态的,缺乏交互性。本章我们希望在预留的filter.html模板内建立表单,从前端向后端提交数据筛选的参数。本章的内容比较容易理解,但对用户体验至关重要,是个细致活。
还是回到上一章对数据本身各字段的分析,这对表单设计也格外重要:
第4章的纸上谈兵本章依然有用
如上图,我们需要有一个必填单选代表一个分析目标字段(我还是习惯称之为breakout字段),它决定返回的数据结果里是品类份额,还是品牌份额,还是其他xx份额。它也是后端Pandas的pivot_table方法里column的动态参数。
我们还需要另外两个必填单选字段——UNIT和PERIOD,原因也请参考上图。
而我们所有的属性字段都是可为空的多选。
本例中我们表单不需要考虑AMOUNT和DATE字段。因为AMOUNT是唯一的指标字段,而我们的分析结果会取最新一个DATE做横断面结果,并计划把所有DATE的数据作为趋势分析,我们不需要对DATE动态选择。而在其他一些场景下,日期字段是经常作为表单的一员的,甚至有很多专门为其设计的calendar控件。
综上所述,我们的表单设计是下面这个样子,我们需要在filter.html文件中实现它。
TC为Therapy Class的简写,可理解为其他行业的不同层级的品类
实际前端模板代码编写前,可以后端先传一个预设的字段字典。这样操作一是分离前端方便以后修改,大部分情况下以后只修改后端就可以了;二是可以利用循环极大缩短代码长度,更加elegant。
我们再次修改views.py里index方法的代码,在context字典内增加表单的预设值传至前端:
# 该字典key为前端准备显示的所有多选字段名, value为数据库对应的字段名
前端html模板filter.html代码如下,为了用户体验,我们希望所有的下拉菜单都使用Semantic UI的search dropdown提供搜索响应功能,主要就是应用这个
class:class="ui fluid search dropdown":
<
这里首先我们第一次遇到了Django/Jinja2模板语法的集中应用,因为本文没有使用Django ORM,这种应用后续出场不多。我们只需要明白{% %}是功能标签,而{{ }}是变量标签,类似在模板层面的简单编程。而下方代码的意思是循环遍历后方传来的mselect_dict字典,字典的key是单选dimension_select下拉菜单选项的text,而value里嵌套的select键的值是菜单选项的value:
<
同理,后续又循环了一次mselect_dict,为根据字典内容生成若干个多选下拉菜单,注释掉的部分是后端动态生成备选项的一种解决方案,本文后半部分会涉及:
<
这里有一个大坑是下面这句,可能会让人觉得很奇怪(这里的|add是tag filter,下一章会解释,这并不是最奇怪的地方):
<
为什么<select name>要加个后缀[]?这是因为以后在jQuery传参时多选控件(实际就是传送array而不是单个变量的控件)的<select name>在很多场景下必须以[]结尾才能正确工作。
但有时[]也不是必须的,这里有一篇详细的文章阐释这个现象,感兴趣的可以做进一步参考,在此就不再赘述了。
How to send FormData objects with Ajax-requests in jQuery?stackoverflow.com
此时再访问我们的主页http://127.0.0.1:8088/chpa/index,界面已经变成了下面这样:
筛选框已经在那了,但下方的多选框点开还没选项,我们还需要一个步骤,从后端动态传入所有多选下拉菜单的备选选项。
此时有两种常用方法:
- 在页面初始化时从后端提取所有字段的不重复值作为选项传入前端。
- 在控件搜索时根据键入关键字实时从后端返回前n个相关备选项。
第一种方法的优点是简单直接。在上方的代码块中,我们其实已经预留了注释掉的相应的代码,将views.py的index方法修改成类似下面这样,增加option_list部分传至前端:
def
再在前端filter.html用下面的循环语句渲染<option></option>部分:
<
很遗憾,功能是实现了,但用户体验很不好。因为我们部分字段的可选项过多,造成页面初始化加载很慢,并且点开选项较多的下拉菜单时反应也很慢。这也是初始化控件选项方法的最大缺点,不适应加载量太大的情况。
下拉菜单的Search Select功能实现了,但加载时间不可接受
但是我们必须使用search select功能,因为医药行业的专业术语太多了。于是考虑使用第二个方法,在控件搜索时根据键入关键字实时从后端返回前n个相关备选项,也就是我们说的on Server Response的方法。该方法适合表单可选项过多的场景。不使用Vue或React的情况下,Semantic UI的dropdown API就支持建设这种响应式搜索功能,并且官网提供了下方的例子:
Match Search Query on Serversemantic-ui.com
本例中实现这种方法确实要相对复杂。我们需要先在views.py建立search方法,该方法除request外包含2个参数,要查询的字段名和查询的字符串,返回不重复的匹配结果作为前端表单选项,格式为符合Semantic UI要求格式的json。
import
上面只是个匹配关键字的最简单例子,未来还可以继续完善,例如处理多个关键字,模糊查询等。
同时,我们需要在url.py编辑对应search方法的URL pattern,并用<>括号预留column和kw两个对应的参数位置:
urlpatterns
此时可在浏览器输入上面的URL试试看效果,能看到已经正常返回预期的json了:
最后参考Semantic UI官网的例子在前端模板文件filter.html末尾加上下面这段JS代码,将后台search方法和多选框绑定。注意下方代码相对复杂有好几个坑,我都在注释一一标出了:
<
在评论区有人回复下面语句会出现bug:
// Semantic UI语法获得多选框默认文本
虽然我个人没有碰到,但是如果有碰到的,可以考虑摒弃Semantic UI API,使用原生的JQuery语句:
var
至此,我们终于完成了大部分前端表单交互的表面工作。本章内容比较繁杂,又第一次在项目中引入了二手程序员的天敌JS,我们在此停笔告一段落。下一章再讨论传参和异步加载的话题。