>>> from env_helper import info; info()
页面更新时间: 2024-04-07 23:44:18
运行环境:
Linux发行版本: Debian GNU/Linux 12 (bookworm)
操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
Python版本: 3.11.2
6.3. Jinja2模板引擎的用法¶
Jinja2是基于python的模板引擎,功能比较类似于于PHP的smarty,J2ee的Freemarker和velocity。 它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。Jinja2使用BSD授权。
Jinja2是Python下一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能。其中最显著的一个是增加了沙箱执行功能和可选的自动转义功能。
优点:
沙箱执行模式,模板的每个部分都在引擎的监督之下执行,模板将会被明确地标记在白名单或黑名单内,这样对于那些不信任的模板也可以执行。
强大的自动HTML转义系统,可以有效地阻止跨站脚本攻击。
模板继承机制,此机制可以使得所有的模板都具有相似一致的布局,也方便了开发人员对模板的修改和管理。
高效的执行效率,Jinja2引擎在模板第一次加载时就把源码转换成Python字节码,加快模板执行时间。
可选的预编译模式。
调试系统融合了标准的Python的TrackBack系统,使得模板编译和运行期间的错误能及时被发现和调试。
语法可配置,可以重新配置Jinja2使得它更好地适应LaTeX或JavaScript的输出。
6.3.1. 安装¶
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
。
6.3.2. 基本结构¶
模板仅仅是文本文件。它可以生成任何基于文本的格式(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 %}
改成
<% foo %>
或类似的东西。
这里有两种分隔符: {% ... %}
和 {{ ... }}
。{% ... %}
用于执行语句,{{ ... }}
输出语句结果到模板。
了解了这些Jinja2的使用就基本掌握了,需要的是一些细节信息。
6.3.3. 变量¶
应用把变量传递到模板,你可能在模板中弄混。变量上面也可以有你能访问的属性或元素。变量看起来是什么,完全取决于应用提供了什么。
你可以使用点( .
)来访问变量的属性,作为替代,也可以使用所谓的“下标”语 法( []
)。下面的几行效果是一样的:
{{ 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
6.3.4. 注释及转义¶
注释
要把模板中一行的部分注释掉,默认使用 {# … #} 注释语法。
{#
{% 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!'
转义
有时想要或甚至必要让 Jinja
忽略部分,不会把它作为变量或块来处理。例如,如果
使用默认语法,你想在在使用把 {{
作为原始字符串使用,并且不会开始一个变量
的语法结构,你需要使用一个技巧。
最简单的方法是在变量分隔符中( {{
)使用变量表达式输出:
{{ '{{' }}
>>> template = Template('Hello {% for user in users -%} {{ "{{" }} {%- endfor %} {{ name }}!')
>>> template.render(users=["Jerry","Bob","Jack"],name="Tom")
'Hello {{{{{{ Tom!'
6.3.5. 模板继承¶
Jinja
中最强大的部分就是模板继承。模板继承允许你构建一个包含你站点共同元素的基
本模板“骨架”,并定义子模板可以覆盖的 块 。
听起来复杂,实际上很简单。从例子上手是最易于理解的。
基本模板¶
这个模板,我们会把它叫做 base.html ,定义了一个简单的 HTML 骨架文档,你可 能使用一个简单的两栏页面。用内容填充空的块是子模板的工作:
<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
标签
告诉模板引擎子模板可以覆盖模板中的这些部分。
子模板¶
子模板是为了将基模板的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" %}
6.3.6. 控制结构清单¶
控制结构指的是所有的那些可以控制程序流的东西 —— 条件(比如
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 '
If语句¶
Jinja
中的 if
语句可比 Python 中的 if
语句。在最简单的形式中,你可以测试 一个变量是否未定义,为空或 false
:
>>> 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 %}
6.3.7. 利用jinja2进行渲染¶
Environment:这个类的实例用于存储配置和全局对象,然后从文件系统或其他位置中加载模板。
FileSystemLoader:文件系统加载器,不需要模板文件存在某个Python包下,可以直接访问系统中的文件。
创建一个Environment加载器对象:
>>> from jinja2 import FileSystemLoader,Environment
>>> env = Environment(loader=FileSystemLoader('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_namen18n</body>n</html>'