本文已收录于 《pyecharts 开发专辑》 。
django-echarts 是本人正在开发的一个开源项目,该项目旨在将 pyecharts 库整合到Django web框架中,从而形成echarts-python-django 大整合的项目。
继之前简单的一个使用示例之后,最近花了几天完成了一种的一个功能插件:js依赖文件管理。
1 Django-Echarts概述
django-echarts这个项目的目标和pyecharts是一致的,即在目标html页面上渲染图表。要完成一个Echarts图表,从最后渲染完成的HTML结构来看,至少应当包含以下三个部分:
- 图表容器控件,比如
<div id="id_mycharts"></div>
- js依赖文件,比如
<script src='/static/echarts/echarts.min.js'></script>
- 图表初始化代码,代码中
myCharts.setOptions(Foo)
所在的script标签。
这个排序按照一般出现的顺序,将所有 script 标签放置在body标签的最后,有利于页面的加载。
在这一过程中,pyecharts 项目为此做了大量的工作,使得我们能够快速地依据功能要求构建出模板渲染所需的数据,这些数据在Django模板系统中称之为 Context。
在实际应用过程中,每个页面的结构都是各式各样的,不能一概而论,因此django-echarts的主要职责:
- 如何创建上述三个标签(代码片段)。
- 上述标签在目标html的位置和结构由用户选择。
- 对于一些简单的页面,可以提供一些shortcut工具。
2 设计思路
2.1 目标
三者之前没有太大的关联性,是可以单独拿出来讨论其设计思想和实现方式的。js 依赖文件管理最终的目标是构建js文件路径字符串。
1 | <script src='/static/echarts/echarts.min.js'></script> |
虽然最后生成的是一个或多个script标签,但依据 Django MTV 原则,标签的构建应当由模板系统负责。
核心的src属性由路径和js文件名两部分组成。路径的意义在于,对于同一个 echarts.min.js 可以由不同的地方提供,这称之为repository。而文件名是由用户输入提供的。使用代码表示如下:
1 | def generte_js_link(js_name): |
2.2 问题
综上所述,js 依赖文件管理解决的问题:
- 需要管理哪些依赖文件
- 哪些repository可以提供js文件,其中哪些可以实现对其的支持。
- 如何在不同repository之间尽可能平稳的切换,即它们之间必须提供统一的API
- 需要对外提供哪些API,即在哪些情况下可能使用到这个功能
3 仓库(repository)与文件
按照正常逻辑,文件名由用户根据实际功能需求指定,其有效性应当交由用户确保。在实际过程不同repository可提供的文件是不一样。js文件分为核心库文件和地图数据文件两种。pyecharts能够提供本地和远程两种类型的repository,加上Django整合时,项目静态文件也可以作为一种repository存在,因此共有三种。
将repository和文件类型进行交叉分析,可整理出以下的一张表格:
仓库 | 核心库文件 | 地图数据文件 | 核心库版本支持 | 远程/ 本地 |
---|---|---|---|---|
pyecharts本地 | 可提供 | 可提供 | 无,不可控 | 本地 |
pyecharts远程 | 可提供 | 可提供 | 无,不可控 | 远程 |
官方CDN | 不提供 | 提供 | - | 远程 |
公共CDN | 可提供 | 不提供 | 支持 | 远程 |
项目静态目录 | 可自定义 | 可自定义 | 可自定义 | 本地 |
分析如下:
- 首先的是pyecharts本地作为存储仓库是不太合适,同为本地文件存储,Django项目静态库显然是一个更为合适的选择。
- pyecharts远程库,路径为 https://chfw.github.io/jupyter-echarts/echarts, 该库的优势在于提供了一些列的自定义地图,但弱势是核心库文件没有版本管理,而且 github 仓库不建议作为静态文件托管服务。
- 官方CDN:其实指的是地图文件数据下载的源地址。
- 公共CDN:优势在于支持版本管理,缺点是不提供地图数据文件。公共CDN仅选择Echarts官方教程提及的三个CDN,其余的已经很久没有更新了。
- 项目静态目录:通常由
setttings.STATIC_URL
指定。 这是开发者自己从零开始构建的,因此自由度最大。为了方便,可开发从其他远程仓库下载文件的功能。
一个通常的使用场景如下:
- 试验django-echarts,仅使用远程仓库,这样不必配置静态文件设置等。
- 如果可用,通过下载工具下载到本地,并进行一系列开发。
- 部署上线时,根据需要切换到CDN。
4 配置
4.1 基本配置
配置是项目初始化需要使用的。默认的配置如下:
1 | DEFAULT_SETTINGS = { |
在实际运行之前,会将用户自定义配置和默认配置进行合并,并向外提供统一的模块变量用于访问。
关于这一部分可以期待之后的《django-echarts系列:配置模块》一文。
由于核心库文件和地图数据文件需要分开托管,因此需要使用两个变量分别指定和设置。二者都有自己有效的可选值。
4.2 远程/本地切换
local_host
的作用有两点:
- 提供公用变量,当
lib_js_host
和map_js_host
同时指定本地仓库时,可以借助该变量 - 下载工具的目标目录。
5 运行分析
5.1 分开托管和文件识别
由于不同仓库提供的文件不同,通常分为可提供核心库文件和地图数据文件,因此需要分别两个查询表(在Python使用一个dict表示即可)。
这就带来了一个问题:用户输入的是 js_name,只有这个参数,而且由于自定义地图文件,理论上可以是任何一个有效的文件名字符串,如何识别为核心库文件还是地图数据文件,即从哪个字典查询,成了一个待解决的问题。
这个没有一个百分百正确的答案。目前采用一个简单办法:由于公共CDN提供的核心库文件是一定的,可提供一个核心库文件列表,判断js_name是否在其中即可。
5.2 输出URL
当确定完某一个仓库后,之后的url构建就比较简单了,本质上来说是python string format的一些封装。仓库路径具体和一些因素有关,这些因素都需要在项目初始化就已经确定了,放在 settings 模块是最为合适了。目前支持以下字段:
- echarts_version:版本字符串,一些公共CDN需要指定版本号。
- STATIC_URL:静态文件目录,通常用于项目本地仓库,该值等于
settings.STATIC_URL
.
在实现过程中,也有两点问题需要注意:
- 字段的大小写问题,为了和
settings.STATIC_URL
一致,也采用了大写变量 - 目录后缀
/
,依据Django规范 STATIC_URL是带有/的,而pyecharts的远程路径没有带有/,以及自己设置的第三方CDN中,这个问题需要作统一处理。目前是按照pyecharts没有带有/,不排除之后会依照Django规范,但是对外部使用是没有任何影响的。
基本代码
1 |
|
5.3 渲染html
这一过程是Django模板系统负责的,为了方面可以自定义一个模板标签echarts_js_dependencies解决这个问题。
以下是基本代码
1 |
|
有几个注意点:
- 标签是支持多个script渲染的。
- 为了方便,列表的每一项支持 文件名或者
pyecharts.base.Base
对象。 - 在多个标签输出时,需要去掉那些重复的文件。
- 因为html结构简单,所以使用
register.simple_tag
就可以了。
6 CLI与Django命令
基于 django manage command 实现一个简单的 CLI,其核心功能是js文件下载。
下载工具提供将远程的js文件同步到本地静态文件目录中。该功能为manage命令,需符合其的一些用法规范。
1 | usage: manage.py download_echarts_js [-h] [--version] [-v {0,1,2,3}] |
远程仓库的选择和限制条件可以使用伪代码表示如下:
1 | host = '' |
本地仓库的选择:只有一个限制条件就是符合本地仓库的要求,即必须以 settings.STATIC_URL 开头。
在配置方面(源目录、目标目录)仅支持 DJANGO_ECHARTS
,暂时还不支持命令行参数传入。这是下一阶段的重点内容。
7 和pyecharts的异同
7.1 扩展和取舍
Django-Echarts是pyecharts在Django环境的适配,在此过程中难免有所扩展和舍弃。
- 在本地存储(离线模式)中,使用Django项目静态目录取代pyecharts本地js存储,并提供一个下载工具将远程js文件下载到Django静态目录,以便平稳过渡。
- 提供一些常用CDN。
- 分析ECharts组成,提供一些模板标签渲染Echarts的每个部件。
由于 pyecharts 尚未实现本地 js 库的完全独立,django_echarts 只是从形式上实现独立,在实际运行过程中还会引用js相关内容,期待pyecharts在这方面有所发展。
7.2 展望
本项目是基于 pyecharts 而发展的。pyecharts是一个非常棒的项目,解决在Python中使用echarts的问题,加强了Python在数据可视化方面的应用。
另一方面pyecharts刚刚面世两三个,目前着重于Echarts实例创建这一问题上,对于外围环境的问题涉及有所不足。