Flask的Jinja2模板引擎 — 自定义扩展(8th)

  • Flask的Jinja2模板引擎 — 自定义扩展(8th)已关闭评论
  • A+
所属分类:python

说实话,关于自定义扩展的开发,Jinja2的官方文档写得真心的简单。到目前为止网上可参考的资料也非常少,你必须得好好读下源码,还好依然有乐于奉献的大牛们分享了些文章来帮助我理解怎么开发扩展。本文我就完全借鉴网上前人的例子,来给大家演示一个Jinja2的自定义扩展的开发方法。

Pygments

Pygments是Python提供语法高亮的工具,官网是pygments.org。我们在介绍Jinja2的自定义扩展时为什么要介绍Pygments呢?因为Jinja2的功能已经很强了,我一时半会想不出该开发哪个有用的扩展,写个没意义的扩展嘛,又怕误导了读者。恰巧网上找到了一位叫Larry的外国友人开发了一个基于Pygments的代码语法高亮扩展,感觉非常实用。他的代码使用了MIT License,那就我放心拿过来用了,不过还是要注明下这位Larry才是原创。

你需要先执行”pip install pygments”命令安装Pygments包。代码中用到Pygments的部分非常简单,主要就是调用”pygments.highlight( )”方法来生成HTML文档。Pygments强的地方是它不把样式写在HTML当中,这样就给了我们很大的灵活性。开始写扩展前,让我们预先通过代码

生成样式内容并将其保存在”static/css/style.css”文件中。这个css文件就是用来高亮语法的。

想深入了解Pygments的朋友们,可以先把官方文档看一下。

编写扩展

我们在Flask应用目录下,创建一个”pygments_ext.py”文件,内容如下:

这段程序解释起来太麻烦,我就把注释都写在代码里了。总的来说,扩展中核心部分就在”parse()”函数里,而最关键的就是这个”parser”对象,它是一个”jinja2.parser.Parser”的对象。建议大家可以参考下它的源码。我们使用的主要方法有:

    • parser.stream 获取当前的文档处理流,它可以基于文档中的行迭代,所以可以使用”next()”方法向下一行前进,并返回当前行
    • parser.parse_expression() 解析下一个表达式,并将结果返回
    • parser.parse_statements() 解析下一段语句,并将结果返回。可以连续解析多行。它有两个参数
      1. 第一个是结束位置”end_tokens”,上例中是”{% endcode %}”标签,它是个列表,可是设置多个结束标志,遇到其中任意一个即结束
      2. 第二个是布尔值”drop_needle”,默认为False,即解析完后流的当前位置指向结束语句”{% endcode %}”之前。设为True时,即将流的当前位置设在结束语句之后

在”parse()”函数最后,我们创建了一个”nodes.CallBlock”的块节点对象,并将其返回。初始化时,我们先传入了”_pygmentize()”方法的调用;然后两个空列表分别对应了字段和属性,本例中用不到,所以设空;再传入解析后的语句块”body”。”CallBlock”节点初始化完后,还要记得将当前行号设置进去。接下来,我们对于语句块的所有操作,都可以写在”_pygmentize()”方法里了。

“_pygmentize()”里的内容我就不多介绍了,只需要记得声明这个方法时,最后一定要接收一个参数caller,它是个回调函数,可以获取之前创建”CallBlock”节点时传入的语句块内容。

使用自定义扩展

扩展写完了,其实也没几行代码,就是注释多了点。现在我们在Flask应用代码中将其启用:

然后让我们在模板中试一下:

运行下,页面上这段代码是不是有VIM的效果呀?这里我们引入了刚才创建在”static/css”目录下”style.css”样式文件,另外千万别忘了要将自动转义关掉,不然你会看到一堆的HTML标签。

另外提醒下大家,网上有文章说,对于单条语句,也就是不需要结束标志的语句,”parse()”函数里无需调用”nodes.CallBlock”,只需返回”return self.call_method(xxx)”即可。别相信他,看看源码就知道,这个方法返回的是一个”nodes.Expr”表达式对象,而”parse()”必须返回一个”nodes.Stmt”语句对象。

完整实例:jinja2-8.tar

weinxin
微信公众号
扫一扫关注运维生存时间公众号,获取最新技术文章~