Jinja2是基于python的模板引擎,功能比较类似于于PHP的smarty, J2ee的Freemarker和velocity。 它能完全支持unicode,并具有集成的沙箱执行环境, 应用广泛。Jinja2使用BSD授权。
Jinja2是Python下一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎, 并扩展了其语法和一系列强大的功能。其中最显著的一个是增加了沙箱执行功能和可选的自动转义功能。
优点如下:
- 沙箱执行模式,模板的每个部分都在引擎的监督之下执行,模板将会被明确地标记在白名单或黑名单内, 这样对于那些不信任的模板也可以执行。
- 强大的自动HTML转义系统,可以有效地阻止跨站脚本攻击。
- 模板继承机制,此机制可以使得所有的模板都具有相似一致的布局,也方便了开发人员对模板的修改和管理。
- 高效的执行效率,Jinja2引擎在模板第一次加载时就把源码转换成Python字节码,加快模板执行时间。
- 可选的预编译模式。
- 调试系统融合了标准的Python的TrackBack系统,使得模板编译和运行期间的错误能及时被发现和调试。
- 语法可配置,可以重新配置Jinja2使得它更好地适应LaTeX或JavaScript的输出。
# pip install jinja2
导入一个模块测试,写一个简单的例子。
from jinja2 import Template
template = Template('Hello {{ name }}!')
template.render(name='John Doe')
'Hello John Doe!'
通过创建一个 Template 的实例,会得到一个新的模板对象,
提供一 个名为 render()
的方法,该方法在有字典或关键字参数时调用扩充模板。
字典或关键字参数会被传递到模板,即模板“上下文”。
Jinja2 内部使用 unicode
并且返回值也是 unicode
字符串。
所以确保应用里也确实使用 unicode
。
基本结构
模板仅仅是文本文件。它可以生成任何基于文本的格式(HTML、XML、CSV、LaTex 等等)。
它并没有特定的扩展名, .html
或 .xml
都是可以的。
模板包含 变量 或 表达式 ,这两者在模板求值的时候会被替换为值。模板中 还有标签,
控制模板的逻辑。模板语法的大量灵感来自于 Django 和 Python 。
下面是一个最小的模板,它阐明了一些基础。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="navigation">
{% for item in navigation %}
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor %}
</ul>
<h1>My Webpage</h1>
{{ a_variable }}
</body>
</html>
{{ foo.bar }}
{{ foo['bar'] }}
花括号不是变量的一部分,而是打印语句的一部分。 如果变量或属性不存在,会返回一个未定义值。可以对这类值做什么取决于应用的配 置, 默认的行为是它如果被打印,其求值为一个空字符串,并且可以迭代它,但其它操作会失败。
过滤器
变量可以通过 过滤器 修改。过滤器与变量用管道符号( |
)分割,
并且也可以用圆括号传递可选参数。多个过滤器可以链式调用,
前一个过滤器的输出会被作为 后一个过滤器的输入。
safe
渲染时值不转义capitialize
把值的首字母转换成大写,其他子母转换为小写lower
把值转换成小写形式upper
把值转换成大写形式title
把值中每个单词的首字母都转换成大写trim
把值的首尾空格去掉striptags
渲染之前把值中所有的HTML标签都删掉join
拼接多个值为字符串replace
替换字符串的值round
默认对数字进行四舍五入,也可以用参数进行控制int
把值转换成整型
使用方法:
template = Template('Hello {{ "abc" | upper }}!')
template.render()
'Hello ABC!'
template = Template('Hello {{ "abc" | title }}!')
template.render()
'Hello Abc!'
方法还有很多这只是比较常见的几个。查看地址 http://docs.jinkan.org/docs/jinja2/templates.html#builtin-filters。
{#
{% for user in users %}
...
{% endfor %}
#}
template = Template('Hello {# {% for user in users %}{{ user }}{% endfor %}#} {{ name }}!')
template.render(users=["Jerry","Bob","Jack"],name="Tom")
'Hello Tom!'
template = Template('Hello {% for user in users %} {{ user }} {% endfor %} {{ name }}!')
template.render(users=["Jerry","Bob","Jack"],name="Tom")
'Hello Jerry Bob Jack Tom!'
默认配置中,模板引擎不会对空白做进一步修改,
所以每个空白(空格、制表符、换行符 等等)都会原封不动返回。
如果应用配置了 Jinja
的 trim_blocks
,
模板标签后的第一个换行符会被自动移除。
此外也可以手动剥离模板中的空白。
当在块(比如一个 for
标签、一段注释或变 量表达式)的开始或结束放置一个减号( -
),
可以移除块前或块后的空白:
template = Template('Hello {% for user in users -%} {{ user }} {%- endfor %} {{ name }}!')
template.render(users=["Jerry","Bob","Jack"],name="Tom")
'Hello JerryBobJack Tom!'
template = Template('Hello {% for user in users -%} {{ "{{" }} {%- endfor %} {{ name }}!')
template.render(users=["Jerry","Bob","Jack"],name="Tom")
'Hello {{{{{{ Tom!'
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2008 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
{% block %}
标签定义了四个子模板可以填充的块。
所有的 block
标签告诉模板引擎子模板可以覆盖模板中的这些部分。
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome on my awesome homepage.
</p>
{% endblock %}
{% extend %}
标签是这里的关键。它告诉模板引擎这个模板“继承”另一个模板。
当模板系统对这个模板求值时,首先定位父模板。这有点像java里子类继承父类,
在将父类的方法进行重写。
模板的文件名依赖于模板加载器。例如 FileSystemLoader
允许用文件名访问其它模板。
可以使用斜线访问子目录中的模板:
{% extends "layout/default.html" %}
控制结构清单
控制结构指的是所有的那些可以控制程序流的东西,
条件(比如 if
/elif
/else
)、for
循环、以及宏和块之类的东西。
控制结构在默认语法中以 {% .. %}
块的形式出现。
语法与Python基本相同,只要注意几个细节就可以完全掌握。
For
循环
遍历序列中的每项。例如,要显示一个由 users 变量提供的用户列表,
值得注意的是loop
属性,在一个 for
循环块中可以访问这些特殊的变量:
loop.index
当前循环迭代的次数(从 1 开始)loop.index0
当前循环迭代的次数(从 0 开始)loop.revindex
到循环结束需要迭代的次数(从 1 开始)loop.revindex0
到循环结束需要迭代的次数(从 0 开始)loop.first
如果是第一次迭代,为 True 。loop.last
如果是最后一次迭代,为 True 。loop.length
序列中的项目数。loop.cycle
在一串序列间期取值的辅助函数。
这个循环 10 次迭代之后会终止处理:
template = Template('{% for user in users %}{% if loop.index >= 10 %}{% else %} {{ user }} {% endif %} {% endfor %}')
template.render(users=[1,2,3,4,5,6,7,8,9,10,11])
' 1 2 3 4 5 6 7 8 9 '
template = Template('Hello {% for user in users %}{% if user %} {{ user }} {% else %} empty {% endif %}{% endfor %}')
template.render(users=["Jerry","Bob","","Jack"])
'Hello Jerry Bob empty Jack '
If语句可用的条件操作符:
==
比较两个对象是否相等。!=
比较两个对象的不等式。>
如果左侧大于右侧,则为true。>=
如果左侧大于或等于右侧,则为true。<
如果左侧小于右侧,则为true。<=
如果左侧小于或等于右侧,则为true。
If语句逻辑连接符:
and
如果左右操作数为真,则返回true。or
如果左操作数或右操作数为真,则返回true。not
非,not x
:如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。
{% macro input(name, value='', type='text', size=20) -%}
<input type="{{ type }}" name="{{ name }}" value="{{value|e }}" size="{{ size }}">
{%- endmacro %}
在命名空间中,宏之后可以像函数一样调用:
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>
如果宏在不同的模板中定义,需要首先使用 import
。
定义宏(forms.html
):
{% macro input(name, value='', type='text') -%}
<input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}
{%- macro textarea(name, value='', rows=10, cols=40) -%}
<textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
}}">{{ value|e }}</textarea>
{%- endmacro %}
使用宏(forms.html
):
{% import 'forms.html' as forms %}
<dl>
<dt>Username</dt>
<dd>{{ forms.input('username') }}</dd>
<dt>Password</dt>
<dd>{{ forms.input('password', type='password') }}</dd>
</dl>
<p>{{ forms.textarea('comment') }}</p>
或者:
{% from 'forms.html' import input as input_field, textarea %}
宏与宏之间的交互:
{% macro render_dialog(title, class='dialog') -%}
<div class="{{ class }}">
<h2>{{ title }}</h2>
<div class="contents">
{{ caller() }}
</div>
</div>
{%- endmacro %}
{% call render_dialog('Hello World') %}
This is a simple dialog rendered by using a macro and
a call block.
{% endcall %}
from jinja2 import FileSystemLoader,Environment
env = Environment(loader=FileSystemLoader('/data/demo/templates'))
get_template()
:获取模板目录下的某个具体文件。
加载一个模板文件:
template = env.get_template('base.html')
render()
:接受变量,对模板进行渲染。
渲染,将模板内的变量进行处理。
template.render(name="test_name",age=18)
'<html lang="en">\n <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n<head>\n <title>\n My Webpage \n</title>\n</head>\n<body>\n \n<h1></h1>\n test_name\n18\n</body>\n</html>'