声明:本文为作者学习总结,内容浅薄。有写的不对的地方,望读者不吝赐教。
三种基本模式
{%语句%} ##语句,控制结构
{{变量}} ##打印模板输出的表达式(变量)
{#……#} ##注释(“……”可包含多行)
访问变量
访问变量有两种方式。
{{ foo.bar }}
这种方式下的实现为:
- 检查 foo 上是否有一个名为 bar 的属性。
- 如果没有,检查 foo 中是否有一个 'bar' 项 。
- 如果没有,返回一个未定义对象。
第二种方式为:
{{ foo['bar'] }}
在这种方式下,其实现为:
- 检查在 foo 中是否有一个 'bar' 项。
- 如果没有,检查 foo 上是否有一个名为 bar 的属性。
- 如果没有,返回一个未定义对象。
过滤器
变量可以通过过滤器进行修改,并且过滤器可链式调用(前一个的输出作为后一个的输入)。形如:
{{ name|striptags|title }} ##移除 name 中的所有 HTML 标签并且改写 为标题样式的大小写格式
{{ list|join(', ') }} ##把一个列表用逗号连接起来
测试
要测试一个变量或表达式,你要在变量后加上一个 is 以及测试的名称。测试也可以接受参数。如果测试只接受一个参数,你可以省去括号来分组它们。形如:
{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}
空格控制(?)
Jinja2语句占据的空行,你自己输出的空格,Tab都将保留。
举例:
<div>
{% if True %}
yay
{% endif %}
</div>
渲染后:
<div>
yay
</div>
要去掉Jinja2语句占据的空行,可以通过设置Jinja2的环境变量实现:
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
渲染后结果如下:
<div>
yay
</div>
也可通过添加“-”的方式达到去除空白的效果。加一个减号 “-”
到块的开始或结束、注释或变量表达式,将删除该块之前或之后的空白。需要注意的是,-和标记之间没有空白(空格、制表符等)。
{%- if foo -%}...{% endif %} ##正确
{% - if foo - %}...{% endif %} ##无效
转义
当你想输出{{时,可使用以下方法。
{{ '{{' }}
对于较大的段落,如果不想让jinja处理它,可标记一个块为raw。如下所示。
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
在这个例子中,jinja不会处理{% raw %}和{% endraw %}两行中包含的行。
行语句
启用行语句,可以简化编辑的过程。例如如果行语句前缀配置为 # ,下面的两个例子是等价的:
<ul>
# for item in seq
<li>{{ item }}</li>
# endfor
</ul>
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
jinja会把带有行语句前缀(这里配置为#)的行视为语句({%%})。
为了语句有更好的可读 性,可在块的开始(比如 for 、 if 、 elif 等等)以冒号结尾。以下例子是可行的。
# for item in seq:
...
# endfor
若有未闭合的圆括号、花括号或方括号,行语句可以跨越多行。以下例子是可行的。
<ul>
# for href, caption in [('index.html', 'Index'),
('about.html', 'About')]:
<li><a href="{{ href }}">{{ caption }}</a></li>
# endfor
</ul>
从 Jinja 2.2 开始,行注释也可以使用了。如果将行注释前缀配置为##, “##语句”会被视为“{#语句#}”,行中所有 ## 之后的内容(不包括换行符)会被忽略。下面是一个例子。
# for item in seq:
<li>{{ item }}</li> ## this comment is ignored
# endfor
模板继承
可定义父模板作为“模板骨架”,在其中定义块;定义子模板继承父模板,填充父模板中定义的块即可,而无需全部编写。一个简单的例子如下。
##父模板base.html
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>
{% block content %}{% endblock %}
##子模版
{% extends "base.html" %}
{% blcok content %}
<p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
{% endblock %}
父模板
在父模板中,可用{% block 块名 %}定义块。块中也有父模板的具体实现,也可不实现。
子模板
子模板首行应继承父模板,{% entends “父模板名” %}。
模板的文件名依赖于模板加载器。例如 FileSystemLoader 允许你用文件名访 问其它模板。你可以使用斜线访问子目录中的模板:
{% extends "layout/default.html" %}
这种行为也可能依赖于应用内嵌的 Jinja 。
子模板并非并非必须定义父模板中的每个块,因此在父模板中,可使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块。子模板中未定义的块,会使用父模板中的值。
不能在一个模板中定义多个同名的块。如果想多次打印一个块,可使用self变量并调用与块同名的函数(此函数是自动生成的)。如下所示。
<title>{% block title %}{% endblock %}</title>
<h1>{{ self.title() }}</h1>
{% block body %}{% endblock %}
在子模板中,可通过调用super()来获得父模板中块的内容。
命名块结束标签
可在块结束标签{% endblock %}中添加块名({% endblock 块名 %}),以增强可读性。并非必须指定块名,但指定块名有助于确定结束的是哪个块。
嵌套块和作用域
默认的块不允许访问块外作用域中的变量。见下例。
{% for item in seq %}
<li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}
模板中定义”list”块并访问循环中的”item”变量。
这个例子会输出空的<li>项,因为item在块中不可用。要使其在块中可用,可在块声明中添加scope,就把块设定到了作用域中。
{% for item in seq %}
<li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}
当覆盖一个块时,不需要提供 scoped 修饰。
模板对象
可通过上下文传递一个模板对象到模板,而模板可以继承这个模板对象,通过以下语句。
{% extends layout_template %}
应当注意,layout_template 变量一定是布局模板文件名的字符串。
HTML转义
从模板生成HTML时,变量可能包含影响已生成HTML的字符。要解决这个问题,可使用手动转义和自动转义。
手动转义
应当转义 可能 包含 > 、 < 、 & 或 " 字符的变量,除非变量中的 HTML 有可信的良好格式。转义通过用管道传递到过滤器 |e 来实现: {{ user.username|e }} 。
自动转义
自动转义会转义除被标记为安全的变量外所有的变量。可以在应用中 标记,也可以在模板中使用 |safe 过滤器标记。
返回模板数据(宏、 super 、 self.BLOCKNAME )的函数,其返回值总是被标记 为安全的。模板中的字符串字面量在自动转义中被也被视为是不安全的。
控制结构
for
举例如下:
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% else %}
<li><em>no users found</em></li>
{% endfor %}
</ul>
与python不同,模板中的循环不可使用break或continue。
在 for 循环中,可以使用特殊的 loop.cycle 辅助函数,伴随循环在一个字符串/变 量列表中周期取值:
{% for row in rows %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
循环递归?
if
与python中的if相似。
宏
与函数类似。举例如下:
##宏定义
{% 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。
在宏内部,有三个可以访问的内部变量。
varargs
如果有多于宏接受的参数个数的位置参数被传入,它们会作为列表的值保存在 varargs 变量上。
kwargs
同 varargs ,但只针对关键字参数。所有未使用的关键字参数会存储在 这个特殊变量中。
caller(?)
如果宏通过 call 标签调用,调用者会作为可调用的宏被存储在这个 变量中。
此外,以下宏属性可访问。
name
宏的名称。 {{ input.name }} 会打印 input 。
arguments
一个宏接受的参数名的元组。
defaults
默认值的元组。
catch_kwargs
如果宏接受额外的关键字参数(也就是访问特殊的 kwargs 变量),为 true 。
catch_varargs
如果宏接受额外的位置参数(也就是访问特殊的 varargs 变量),为 true 。
caller
如果宏访问特殊的 caller 变量且由 call 标签调用,为 true 。
如果一个宏的名称以下划线开始,它不是导出的且不能被导入,参考python中的函数。
调用
宏可以访问调用者语句块的内容,换句话说,宏的”{{ caller( ) }}”部分会被调用者”{% call %}”语句块内部的内容替代。看下面一个例子。
在templates/_list_user.html创建宏”list_users”:
{% macro list_users(users) -%} <table> <tr><th>Name</th><th>Action</th></tr> {%- for user in users %} <tr><td>{{ user.name |e }}</td>{{ caller() }}</tr> {%- endfor %} </table> {%- endmacro %} ———————————————— 原文链接:https://blog.csdn.net/gh254172840/article/details/81745338
宏的作用就是将用户列表显示在表格里,表格每一行用户名称后面调用了”{{ caller( ) }}”方法。
然后在templates/user.html编写调用者的代码:
{% from "_list_user.html" import list_users with context %} {% set users=[{'name':'Tom','gender':'M','age':20}, {'name':'John','gender':'M','age':18}, {'name':'Mary','gender':'F','age':24}] %} {% call list_users(users) %} <td><input name="delete" type="button" value="Delete"></td> {% endcall %} ———————————————— 原文链接:https://blog.csdn.net/gh254172840/article/details/81745338
这里使用了{% call %}语句来调用宏,语句块中包括了一段生成”Delete”按钮的代码。运行后发现每个用户名后面都出现了”Delete”按钮,也就是”{{ caller( ) }}”部分被调用者”{% call %}”语句块内部的内容替代了。
Jinja2的宏不但能访问调用者语句块的内容,还能给调用者传递参数。
在templates/_list_user.html中,将表格增加一列性别,并在宏里调用”caller()”方法时,传入一个变量”user.gender”,如下所示。
{% macro list_users(users) -%} <table> <tr><th>Name</th><th>Gender</th><th>Action</th></tr> {%- for user in users %} <tr><td>{{ user.name |e }}</td>{{ caller(user.gender) }}</tr> {%- endfor %} </table> {%- endmacro %} ———————————————— 原文链接:https://blog.csdn.net/gh254172840/article/details/81745338
修改templates/user.html中调用者语句块,如下所示。
{% from "_list_user.html" import list_users with context %} {% call(gender) list_users(users) %} <td> {% if gender == 'M' %} <img src="{{ url_for('static', filename='img/male.png') }}" width="20px"> {% else %} <img src="{{ url_for('static', filename='img/female.png') }}" width="20px"> {% endif %} </td> <td><input name="delete" type="button" value="Delete"></td> {% endcall %} ———————————————— 原文链接:https://blog.csdn.net/gh254172840/article/details/81745338
我们在使用”{% call %}”语句时,将其改为了”{% call(gender) … %}”,这个括号中的”gender”就是用来接受宏里传来的”user.gender”变量。因此我们就可以在”{% call %}”语句中使用这个”gender”变量来判断用户性别。这样宏就成功地向调用者传递了参数。
————————————————
原文链接:https://blog.csdn.net/gh254172840/article/details/81745338
过滤器
将数据用filter块包裹起来,即可对其应用jinja2过滤器。举例如下。
{% filter upper %}
This text becomes uppercase
{% endfilter %}
赋值
使用set标签,可为多个变量赋值。在顶层的(块、宏、循环之外)赋值是可导出的。当前模板也可以从别的模板中导入赋值。举例如下:
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
继承
你可以在一个文件中使用多次继承,但是 只会执行其中的一个。
这与extends的特性有关——Jinja2 支持动态继承并且只要没有 extends 标签被访问过,就不分辨父模板和子模 板。而这会导致令人惊讶的行为:首个 extends 标签前的包括空白字符的所有东西 会被打印出来而不是被忽略(见jinja2文档“null-master退回”部分)。通常情况下,extends应当放于文件的首行。但有时,我们可以利用这一特性。见下面这个例子。
{% if not standalone %}{% extends 'master.html' %}{% endif -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<title>{% block title %}The Page Title{% endblock %}</title>
<link rel="stylesheet" href="style.css" type="text/css">
{% block body %}
<p>This is the page body.</p>
{% endblock %}
在这个例子中,将extends标签置于if标签中。如果变量standalone为false,就将执行extends标签,继承‘master.html’。
包含
有很多页面的某些内容是一样的,比如“页眉”、“页脚”。开发的时候可以将相同的部分放在独立的模板中,编写时将其“包含”进来即可。举例如下。
##header.html
<style>
.nav ul{
overflow: hidden;
}
.nav ul li{
float: left;
margin: 0 20px;
}
</style>
<nav class="nav">
<ul>
<li>首页</li>
<li>课程详情</li>
<li>教程视频</li>
<li>关于我们</li>
</ul>
</nav>
#footer.html
<h1>footer</h1>
编写页面时,如果需要含有“页眉”、“页脚”,将其“包含”进来即可。如下所示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>include tag demo </title>
</head>
<body>
<!-- 导入header.html -->
{% include 'header.html' %}
<div class="content">
中间内容
</div>
<!-- 导入footer.html -->
{% include 'footer.html' %}
</body>
</html>
如果被包含的模板不存在,会抛出一个异常。可以把一句 include 用 ignore missing 标记,这样如果模板不存在,Jinja 会忽略这条语句。如下所示。
{% include "sidebar.html" ignore missing %}
你也可以提供一个模板列表,它会在包含前被检查是否存在。第一个存在的模板会 被包含进来。如果给出了 ignore missing ,且所有这些模板都不存在,会退化 至不做任何渲染,否则将会抛出一个异常。如下所示。
{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
当与 with 或 without context 语句联合使用时,ignore misssing必须被放在上下文可见性语句(with context或without context)之前 。举例如下。
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}
without context语句让被包含的模板不可以使用视图(就是那个.py文件)传递过来的对象(默认情况下,被包含的模板能够使用视图传递过来的对象)。
Changed in version 2.4: 如果传递一个模板对象到模板上下文,你可以用 include 包含这个对 象。
导入
和python的导入(import)部分极其相似。
导入有两种方式:导入整个模块或导入特定的宏(可视为python中的函数)。
被导入的模块如下。
{% 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 %}
导入整个模块的方式如下。
{% 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 %}
<dl>
<dt>Username</dt>
<dd>{{ input_field('username') }}</dd>
<dt>Password</dt>
<dd>{{ input_field('password', type='password') }}</dd>
</dl>
<p>{{ textarea('comment') }}</p>
给被导入的模板或宏命名,访问被导入的宏的方法与python相似,可参考python。
导入上下文行为
被导入的模板和被包含的模板是不同的:被导入的模板经常只作为容纳宏的模块,不会被缓存,也就无法访问当前模板的上下文(.py视图文件传给它的);而被包含的模板会被缓存,默认可以访问当前模板的上下文。
这可显式更改。
with context:将当前模板的上下文传递到模板,并且允许缓存;
without context:模板无法访问当前模板的上下文,自动禁用缓存。
举例如下。
{% from 'forms.html' import input with context %}
{% include 'header.html' without context %}
值得注意的是:在 Jinja 2.0 中,传递给模板的当前模板的上下文不包含当前模板中定义的变量;而从 Jinja 2.1 开始,传递给模板的当前模板的上下文包含当前模板中定义的变量。
表达式
字面量
字符串、整数、浮点数、列表、元组、字典、true、false均与python中的相同。
注意:如果元组中只有一个项,你需要以逗号 结尾它。
true、false和none应当使用小写的版本。
算术
与python相似。
比较
与python相似。
逻辑
与python相似。
注意:is 和 in 运算符同样支持使用中缀记法: foo is not bar 和 foo not in bar 而不是 not foo is bar 和 not foo in bar 。所有的 其它表达式需要前缀记法 not (foo and bar) 。
其它运算符
in:运行序列/映射包含检查。如果左操作数包含于右操作数,返回 true 。比如 {{ 1 in [1,2,3] }} 会返回 true 。
is:运行一个测试 。
|:应用一个过滤器。
~:把所有的操作数转换为字符串,并且连接它们。 {{ "Hello " ~ name ~ "!" }} 会返回(假设 name 值为 ''John' ) Hello John! 。("+"也可以实现连接字符串,但你应当首选“~”运算符达成这一目的)。
():调用一个可调用量:{{ post.render() }} 。在圆括号中,你可以像在 python 中一样使用位置参数和关键字参数: {{ post.render(user, full=true) }} 。
. / []:获取一个对象的属性。(见“变量”)
内联的if表达式
语法是 <do something> if <something is true> else <do something else> 。举例如下:
{% extends layout_template if layout_template is defined else 'master.html' %}
在一个 变量定义的情况下才继承一个模板,否则继承默认的布局模板。
else 部分是可选的。如果没有显式地提供 else 块,会求值一个未定义对象。
内置过滤器清单
略
内置测试清单
略
全局函数清单
略
扩展
i18n(?)
{% trans %}
{% endtrans %}
表达式语句
如果加载了表达式语句扩展,一个名为 do 的扩展即可用。它工作几乎如同常规的变量 表达式( {{ ... }} ),只是它不打印任何东西(不输出表达式)。这可以用于修改列表:
{% do navigation.append('a string') %}
循环控制
如果应用启用循环控制,则可以在循环中使用 break ({% break %})和 continue({% continue %})语句 。举例如下。
这个循环每两项跳过一次:
{% for user in users %}
{%- if loop.index is even %}{% continue %}{% endif %}
...
{% endfor %}
这个循环10次迭代后会终止处理。
{% for user in users %}
{%- if loop.index >= 10 %}{% break %}{% endif %}
{%- endfor %}
with语句
如果应用启用了 With 语句 ,将允许在模板中使用 with 关键 字。这使得创建一个新的内作用域。这个作用域中的变量在外部是不可见的。举例如下。
{% with foo = 42 %}
{{ foo }}
{% endwith %}
{% with %}
{% set foo = 42 %}
{{ foo }}
{% endwith %}
以上两种写法是等价的。
自动转义扩展
如果你的应用程序设置了自动转义扩展,你就可以在模版中开启或者关闭自动转义。举例如下。
{% autoescape true %}
自动转义在这块文本中是开启的。
{% endautoescape %}
{% autoescape false %}
自动转义在这块文本中是关闭的。
{% endautoescape %}
在 endautoescape 标签之后,自动转义的行为将回到与之前相同的状态。