上一篇介绍了Jinjia2模板系统的基本用法,本篇将深入对Jinjia2进行探讨,对网页设计中经常会用到的一些高级特性进行介绍。
复用是网页设计非常常用的特性,比如我们的页面头部的网站名称和页尾的版权标识通常都是一样的,我们的菜单有时候在每个页面也都是一样的。作为一名程序员,重复做同样的事情是完全不可接受的。在Jinjia2中,通常可以使用继承、包含和宏三种特性来完成模板的利用。
这和类的继承没有什么分别,因此也就有了父模板和子模板的概念。例如,我们可以把包含HTML框架、页头、页尾的模板页做为父模板,其它的子模板只需要继承它,就自动拥有了头部和尾部。
下面是一个父模板的例子:
<html>
<head>
{% block head %}
<title>{% block title %}Base Title{% endblock %} - My Applicationtitle>
{% endblock %}
head>
<body>
<h1>This Header is inherited from base.htmlh1>
{% block body %} {% endblock %}
<hr/>
This footer is inherited from base.html
body>
html>
现在我们在templates目录新建一个文件,写下一行代码,保存为child.html
{% extends "base.html" %}
在创建了Flask app的源代码中加上一个路由/child,完整的代码如下:
import json,pprint,sys
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/child')
def child1():
return render_template("child.html")
if __name__ == '__main__':
app.run(debug=True)
运行这个程序我们看到如下的结果:
注意红色标记的部分,这个页面的title仍然是Base Title,原因是我们在子模板中并没有对{% block title %}进行改写。将child.html扩充:
{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% block body %}<h2> This is body of child1 h2> {% endblock %}
再看看页面的标题已被替换,body部分也被充实了内容。
模板继承中,可以使用一个特殊的super函数,将父模板内容块中定义的内容附加到子模板中,这有点像Python类的super函数。
{% block title%}
Child1 -
{{ super() }}
{% endblock %}
大家可以动手试一下这样写的话页面的标题会变成什么样子。
可以使用include将一个独立的模板文件包含进来,这一点和PHP非常相似。我们继续修改child.html:
{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% include 'menu.html' %}
{% block body %}<h2> This is body of child1 h2> {% endblock %}
同时,新建一个名称是menu.html的模板文件,放置在同一目录下,内容如下:
<hr/>
<ul>
<li>Menu Item 1li>
<li>Menu Item 2li>
<li>Menu Item 3li>
<hr/>
现在的页面已经包含了一个菜单项。
最后我们介绍一下宏。宏的概念和大家了解的Office中的宏很类似,它通常用来做一些需要多次处理的简单工作。Jinjia2中定义和使用宏有点像定义和使用函数,下面继续我们的child.html,在里面添加上宏的定义和调用代码。
{% macro render_comment(comment) %}
<li>MACRO:{{ comment }}li>
{% endmacro %}
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
ul>
我们还可以把宏代码放置在一个单独的文件中,下面我们新建一个文件macros.html,内容如下:
{% macro render_comment_from_file(comment) %}
<li>来自文件:{{ comment }}li>
{% endmacro %}
从文件中载入宏代码用到了一个新的命令import,继续修改child.html,增加以下内容
<h4>这是由从文件导入的宏生成的h4>
{% import 'macros.html' as macros %}
<ul>
{% for comment in comments %}
{{ macros.render_comment_from_file(comment) }}
{% endfor %}
ul>
至此,完整的child.html文件如下:
{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% include 'menu.html' %}
{% block body %}
<h2> This is body of child1 h2>
{% macro render_comment(comment) %}
<li>MACRO:{{ comment }}li>
{% endmacro %}
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
ul>
<h4>这是由从文件导入的宏生成的h4>
{% import 'macros.html' as macros %}
<ul>
{% for comment in comments %}
{{ macros.render_comment_from_file(comment) }}
{% endfor %}
ul>
{% endblock %}
前几章中我们了解到,Jinjia2的工作模式是向模板发送数据再渲染成HTML页面。不过在很多情况下,发送到页面的数据并不是我们期望的格式,这时候就要用到它的格式化功能。
Jinjia2中的格式化操作最常见的是使用过滤器进行的。
我们用一个例子对字符串的格式化操作进行说明,将下面的代码保存为strings.html
<h1>Hello {{user}}h1>
<hr />
<p>转为首字母大写: Hello, {{ user|capitalize }}p>
<p>转为大写: Hello, {{ user|upper }}p>
<p>转为小写: Hello, {{ user|lower }}p>
<p>转为标题样式(每个主题词首字母大写): Hello, {{ user|title }}p>
<p>去掉首尾空格(页面上无效果): Hello, {{ user|trim }}p>
<p>默认的HTML过滤操作: {{ myhtmlstr }}p>
<p>添加safe过滤器(有安全隐患,如果不能确认字符串是安全的请不要使用!): {{ myhtmlstr|safe }}p>
<p>过滤掉HTML标记: {{ myhtmlstr|striptags }}p>
<hr />
在创建了Flask app的源代码中加上一个路由/strings,完整的代码如下:
import json,pprint,sys
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/strings')
def strings():
return render_template("strings.html",user="ivan wang",
myhtmlstr="this is emphasized")
if __name__ == '__main__':
app.run(debug=True)
该页面在浏览器中显示如下
仍然使用一个例子来演示数字的格式化方法,将下面的代码保存为numerics.html:
<h2>和数字相关的过滤器h2>
<p>四舍五入:{{n1|round}}p>
<p>保留3位小数并四舍五入:{{n1|round(3)}}p>
<p>保留1位小数下取整:{{n1|round(1,'floor')}}p>
<p>保留1位小数上取整:{{n1|round(1,'ceil')}}p>
<p>取整:{{n1|int}}p>
<p>使用格式化字符串:{{"%.2f" % n1}}p>
<p>使用string.format函数进行千分位显示:{{"{:,}".format(n2)}}p>
<p>使用string.format函数对多个数字进行格式化:{{"Number1:{0:.2%}, Number2:{1:,}".format(n1,n2)}}p>
在python代码中添加一个numerics路由:
@app.route('/numerics')
def numerics():
return render_template("numerics.html",n1=3.14159,n2=29838721)
页面显示如下:
在Jinja2中使用格式化字符串和String.format为数字和字符的格式化输出带来了无限的可能,更多的信息请参考 https://docs.python.org/2/library/string.html#format-string-syntax。
Jinja2内置了功能丰富的过滤器,可以参考[[http://jinja.pocoo.org/docs/dev/templates]]获取更多的信息。
如果所有内置的过滤器都不能满足要求,Jinja2还允许你创建自定义的过滤器。
添加一个userdefined路由,代码如下:
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
@app.route('/userdefined')
def userdefined():
return render_template("userdefined.html",s="abcdefg")
userdefined.html内容如下:
{{s|reverse}}
请大家自行尝试该模板的渲染结果。