跳转至

Jinja2 模版引擎

概要: jinja2 是一个快速高效的模版引擎

创建时间: 2023.11.05 21:56:06

更新时间: 2023.11.06 01:39:36

安装

Bash
pip install -U Jinja2
jinja2 模板文件没有指定的后缀,可以使用 .jinja 或者任意的文本文件扩展名

{{ ... }} 变量

{{ x }}

如果是单个变量x,可以使用 {{ x }} 语法获取 x 的值

{{ foo.bar }}

类似 Python 的 getattr 函数,可以用于获取对象或者字典的值

{{ foo['bar'] }}

类似 Python 的__getitem__ 方法,也可以用于获取对象或者字典的值

区别

如果一个对象同时拥有上面两种方法,那么不同的调用方式会有优先级之分,如x['foo'] = bar1x.foo = bar2,那么使用{{ foo.bar }}时,渲染的结果是 bar2 ,使用{{ foo['bar'] }}时,渲染结果为 bar1

{% ... %} 逻辑

循环 for...endfor

提示

下面的变量后加上 |e 是为了安全转义,降低 HTML 漏洞攻击概率

列表循环

Bash
1
2
3
4
5
6
<h1>Members</h1>
<ul>
{% for user in users %}
  <li>{{ user.username|e }}</li>
{% endfor %}
</ul>
字典循环
Bash
1
2
3
4
5
6
<dl>
{% for key, value in my_dict.items() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>
字典循环且排序
Bash
1
2
3
4
5
6
<dl>
{% for key, value in my_dict | dictsort %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

特殊属性/方法

对一个可循环的变量,jinja2 内置了一些属性和方法供调用,详细用法可以参考官方文档 for
image.png

提前终止循环

在 jinja2 中无法实现,但是可以通过元素中的属性进行过滤,如

Bash
1
2
3
{% for user in users if not user.hidden %}
    <li>{{ user.username|e }}</li>
{% endfor %}

分支 if...endif

Bash
1
2
3
4
5
6
7
8
9
{% if condition1 %}
    This is condition 1.
{% elif condition2 %}
    This is condition 2.
{% elif condition3 %}
    This is condition 3.
{% else %}
    This is the else block.
{% endif %}

转义 raw...endraw

简短文本可以通过单引号实现转义,如渲染两个尖括号可以使用 {{ '{{' }} 的写法。
如果是较为复杂的场景,需要使用 {% raw %} 实现,如

Bash
1
2
3
4
5
6
7
{% raw %}
    <ul>
      {% for item in seq %}
            <li>{{ item }}</li>
      {% endfor %}
    </ul>
{% endraw %}

macros

TODO,参考 官方文档 Macros

继承 block...extends

单级继承 {{ super() }}

jinja2 通过在上级定义模版块 {{ block }} ,下级使用 {{ extends }} 关键词实现继承。
下面是上级被继承的模板文件 base.html

HTML
<!DOCTYPE html>
<html lang="en">
<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 %}
        {% endblock %}
    </div>
</body>
</html>
下面是下级子文件 child.html,继承自 base.html,其中 {{ super }} 语法用于在上级模板的基础上,继续扩写此 block 的内容
HTML
{% 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 to my awesome homepage.
    </p>
{% endblock %}

block 匹配

在上面的模板中,为了增强可读性,可以使用 {% block head %}{% endblock head %} 这样的 block 对写法

多级继承 {{ super.super() }}

下面三级的文件内容如下,可以使用 {{ super.super() }} 实现只继承顶级模版内容

Bash
# parent.jinja
body: {% block body %}Hi from parent.{% endblock %}

# child.jinja
{% extends "parent.jinja" %}
{% block body %}Hi from child. {{ super() }} {% endblock %}

# grandchild1.jinja
{% extends "child.jinja" %}
{% block body %}Hi from grandchild1.{% endblock %}

# grandchild2.jinja
{% extends "child.jinja" %}
{% block body %}Hi from grandchild2. {{ super() }} {% endblock %}

# grandchild3.jinja
{% extends "child.jinja" %}
{% block body %}Hi from grandchild3. {{ super.super() }} {% endblock %}
渲染结果为
Bash
1
2
3
4
5
body: Hi from parent.
body: Hi from child. Hi from parent. 
body: Hi from grandchild1.
body: Hi from grandchild2. Hi from child. Hi from parent.  
body: Hi from grandchild3. Hi from parent.

block 作用域 scoped

在 block 渲染中,默认的变量作用域仅为当前级别模板,对子级别模板不可见,如在下面的模板中,如果子级别模板继承后,代码段 <li> 内是空的

Bash
1
2
3
{% for item in seq %}
    <li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}
此时,可以通过将 block 标记为 scoped 来显式标记 block 内的变量对子级别模板可见
Bash
1
2
3
{% for item in seq %}
    <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}

block 强制性 required

在下面的三级模板继承中, block body 被标记为必需的 block,否则渲染失败

Bash
1
2
3
4
5
6
7
8
9
# page.txt
{% block body required %}{% endblock %}

# issue.txt
{% extends "page.txt" %}

# bug_report.txt
{% extends "issue.txt" %}
{% block body %}Provide steps to demonstrate the bug.{% endblock %}
其中,只有 bug_report.txt 可以被正常渲染,page.txtissue.txt 会抛出异常 TemplateRuntimeError

scoped 与 required 优先级

required 必须在 scoped 之后出现

  • {% block body scoped %}{% endblock %}
  • {% block body required %}{% endblock %}
  • {% block body scoped required %}{% endblock %}

{# ... #} 注释

单行注释

Bash
{# this is a jinja2 comment line, will not be rendered #}

多行注释

Bash
1
2
3
4
5
{# note: commented-out template because we no longer use this
    {% for user in users %}
        ...
    {% endfor %}
#}

提示

注释虽然不会被渲染,但如果单行和多行注释会表现为一个空行

过滤器 Filter

jinja2 的 Filter 用于对变量的值进行过滤,常用于循环语句中

TODO

测试器 Tests

jinja2 的 Tests 用于对变量的值进行测试,常用于分支语句中

TODO

参考