模板设计器文档

本文档描述了模板引擎的语法和语义,对于创建Jinja模板的人来说,它将是最有用的参考。由于模板引擎非常灵活,应用程序的配置在分隔符和未定义值的行为方面可能与此处显示的代码略有不同。

简介

Jinja模板只是一个文本文件。Jinja可以生成任何基于文本的格式(HTML、XML、CSV、LaTex等)。Jinja模板不需要具有特定的扩展名: .html.xml 或者任何其他扩展都可以。

模板包含 变量 和/或 表达 ,当模板 提供 ;和 tags 控制模板的逻辑。模板语法深受Django和Python的启发。

下面是一个最小的模板,它演示了使用默认的jinja配置的一些基础知识。我们稍后将在本文档中介绍详细信息:

<!DOCTYPE html>
<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 }}

    {# a comment #}
</body>
</html>

以下示例显示默认配置设置。应用程序开发人员可以从 {{% foo %}}<% foo %> 或者类似的东西。

有几种定界符。默认的jinja分隔符配置如下:

  • {% ... %} for Statements

  • {{{{ ... }}}} 对于 表达 打印到模板输出

  • {{# ... #}} 对于 评论 不包括在模板输出中

Line Statements and Comments 也是可能的,尽管它们没有默认的前缀字符。要使用它们,请设置 line_statement_prefixline_comment_prefix 在创建 Environment

模板文件扩展名

如上所述,任何文件都可以作为模板加载,而不考虑文件扩展名。添加 .jinja 延伸,比如 user.html.jinja 可能会使一些ide或编辑器插件更容易,但不是必需的。后面介绍的自动转义可以基于文件扩展名应用,因此在这种情况下,需要考虑额外的后缀。

另一个识别模板的好方法是它们在 templates 文件夹,不考虑扩展名。这是项目的常见布局。

变量

模板变量由传递给模板的上下文字典定义。

如果应用程序传入了模板中的变量,那么您可以随意处理这些变量。变量上可能有属性或元素,您也可以访问它们。变量的属性在很大程度上取决于提供该变量的应用程序。

你可以用圆点 (. )访问除标准python之外的变量属性 __getitem__ “下标”语法 ([]

以下几行的作用相同:

{{ foo.bar }}
{{ foo['bar'] }}

重要的是要知道外部的双花括号是 not 变量的一部分,但打印语句。如果访问标记内的变量,不要在它们周围加括号。

如果变量或属性不存在,您将返回未定义的值。使用这种类型的值可以做什么取决于应用程序配置:默认行为是在打印或迭代时计算为空字符串,并在其他每个操作中失败。

实施

为了方便起见, foo.bar 在Jinja中,在Python层上执行以下操作:

  • 检查调用的属性 barfoo (getattr(foo, 'bar')

  • 如果没有,检查项目 'bar' 在里面 foo (foo.__getitem__('bar')

  • 如果没有,则返回未定义的对象。

foo['bar'] 工作原理基本相同,但顺序差异较小:

  • 检查项目 'bar' 在里面 foo . (foo.__getitem__('bar')

  • 如果没有,请检查调用的属性 barfoo . (getattr(foo, 'bar')

  • 如果没有,则返回未定义的对象。

如果对象具有同名的项和属性,则这一点很重要。另外, attr() 筛选器仅查找属性。

过滤器

变量可以修改为 过滤器 . 过滤器通过管道符号与变量分离。 (| )并且可以在括号中包含可选参数。可以链接多个过滤器。一个过滤器的输出应用于下一个过滤器。

例如, {{{{ name|striptags|title }}}} 将从变量中删除所有HTML标记 name 标题大小写输出 (title(striptags(name))

接受参数的过滤器在参数周围有圆括号,就像函数调用一样。例如: {{{{ listx|join(', ') }}}} 将以逗号加入列表 (str.join(', ', listx)

这个 内置过滤器列表 下面介绍所有内置过滤器。

测验

除了过滤器,还有所谓的“测试”可用。测试可用于根据公共表达式测试变量。要测试变量或表达式,请添加 is 加上变量后面的测试名称。例如,要确定是否定义了变量,可以执行以下操作 name is defined ,然后根据 name 在当前模板上下文中定义。

测试也可以接受参数。如果测试只接受一个参数,则可以省略括号。例如,以下两个表达式执行相同的操作:

{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}

这个 内置测试列表 下面介绍所有内置测试。

评论

要注释模板中的一行的一部分,请使用注释语法,默认设置为 {{# ... #}} . 这对于注释模板的某些部分以进行调试或为其他模板设计器或您自己添加信息很有用:

{# note: commented-out template because we no longer use this
    {% for user in users %}
        ...
    {% endfor %}
#}

空白控件

在默认配置中:

  • 如果存在单个尾随换行符,则去掉尾随换行符。

  • 其他空白(空格、制表符、换行符等)返回时不变

如果应用程序将jinja配置为 trim_blocks ,自动删除模板标记后的第一个换行符(如在PHP中)。这个 lstrip_blocks 选项还可以设置为从一行的开头到块的开头剥离制表符和空格。(如果块开始之前还有其他字符,则不会删除任何内容。)

两者兼有 trim_blockslstrip_blocks 启用后,可以将块标记放在它们自己的行上,渲染时将删除整个块行,保留内容的空白。例如,如果没有 trim_blockslstrip_blocks 选项,此模板:

<div>
    {% if True %}
        yay
    {% endif %}
</div>

在DIV:内用空行呈现:

<div>

        yay

</div>

但两者兼而有之 trim_blockslstrip_blocks 启用后,将删除模板块行并保留其他空白:

<div>
        yay
</div>

您可以手动禁用 lstrip_blocks 加加号的行为 (+ )在块的开头:

<div>
        {%+ if something %}yay{% endif %}
</div>

类似地,您可以手动禁用 trim_blocks 加加号的行为 (+ )在一个街区的末尾:

<div>
    {% if something +%}
        yay
    {% endif %}
</div>

您还可以手动去除模板中的空白。如果你加一个减号 (- )到块的开始或结束(例如 为了 标记)、注释或变量表达式,将删除该块之前或之后的空白:

{% for item in seq -%}
    {{ item }}
{%- endfor %}

这将生成所有元素,它们之间没有空白。如果 seq 是来自 19 ,输出为 123456789 .

如果 行语句 如果启用,它们将自动删除行首空白,直到行首。

默认情况下,Jinja还会删除尾随的换行符。要保持单尾随换行符,请将Jinja配置为 keep_trailing_newline .

注意

不能在标记和减号之间添加空白。

有效的 ::

{%- if foo -%}...{% endif %}

无效 ::

{% - if foo - %}...{% endif %}

逃逸

有时,甚至有必要让Jinja忽略它将作为变量或块处理的部分。例如,如果要使用默认语法 {{{{ 作为模板中的原始字符串而不是变量的开头,必须使用技巧。

输出文本变量分隔符的最简单方法 ({{{{ )是通过使用变量表达式::

{{ '{{' }}

对于较大的部分,标记块是有意义的 raw . 例如,要在模板中包含示例jinja语法,可以使用以下代码段:

{% raw %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

注意

结尾的减号 {{% raw -%}} 标记将清除原始数据第一个字符前面的所有空格和换行符。

行语句

如果应用程序启用了行语句,则可以将行标记为语句。例如,如果行语句前缀配置为 # ,以下两个示例是等效的:

<ul>
# for item in seq
    <li>{{ item }}</li>
# endfor
</ul>

<ul>
{% for item in seq %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

行语句前缀可以出现在行的任何位置,只要行前面没有文本。为了提高可读性,启动块的语句(例如 forifelif 等)可能以冒号结尾:

# for item in seq:
    ...
# endfor

注意

如果有左括号、大括号或括号,则line语句可以跨多行:

<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

模板继承

Jinja最强大的部分是模板继承。模板继承允许您构建一个基本的“骨架”模板,该模板包含站点的所有公共元素并定义 阻碍 子模板可以重写。

听起来很复杂,但很基本。从一个例子开始,很容易理解它。

基本模板

我们将调用此模板 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 %}
        &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.
        {% endblock %}
    </div>
</body>
</html>

在这个例子中, {{% block %}} 标记定义了子模板可以填充的四个块。所有的 block 标记的作用是告诉模板引擎子模板可能会覆盖模板中的那些占位符。

block 标记可以位于其他块中,例如 if ,但无论 if 块实际上已渲染。

子模板

子模板可能如下所示:

{% 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 %}

这个 {% extends %} 标签是这里的关键。它告诉模板引擎这个模板“扩展”了另一个模板。当模板系统评估此模板时,它首先定位父模板。扩展标记应该是模板中的第一个标记。它之前的一切都是正常打印出来的,可能会引起混乱。有关此行为以及如何利用它的详细信息,请参见 空-默认回退 。此外,无论周围的条件被评估为真还是假,块都将始终被填充。

模板的文件名取决于模板加载器。例如, FileSystemLoader 允许您通过提供文件名来访问其他模板。可以使用斜线访问子目录中的模板::

{% extends "layout/default.html" %}

但是这种行为可以依赖于嵌入jinja的应用程序。注意,由于子模板没有定义 footer 块,使用父模板中的值。

不能定义多个 {{% block %}} 起源 . 如果有两个相似的名字 {{% block %}} 标记在模板中,该模板的父级将不知道要使用哪个块的内容。

如果要多次打印一个块,则可以使用 self 变量并使用该名称调用块:

<title>{% block title %}{% endblock %}</title>
<h1>{{ self.title() }}</h1>
{% block body %}{% endblock %}

超级街区

可以通过调用 super() . 这将返回父块的结果:

{% block sidebar %}
    <h3>Table Of Contents</h3>
    ...
    {{ super() }}
{% endblock %}

嵌套延伸

在多个级别的情况下 {{% extends %}}super 引用可以被链接(如 super.super() )跳过继承树中的级别。

例如::

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

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

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

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

致使 child.tmpl 将给予 body: Hi from child. Hi from parent.

致使 grandchild1.tmpl 将给予 body: Hi from grandchild1.

致使 grandchild2.tmpl 将给予 body: Hi from grandchild2. Hi from parent.

命名块结束标记

Jinja允许您将块的名称放在结束标记之后,以提高可读性:

{% block sidebar %}
    {% block inner_sidebar %}
        ...
    {% endblock inner_sidebar %}
{% endblock sidebar %}

但是,名称后面的 endblock Word必须与块名称匹配。

块嵌套和范围

块可以嵌套用于更复杂的布局。但是,每个默认块可能无法从外部作用域访问变量:

{% for item in seq %}
    <li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}

此示例将输出为空 <li> 项目因为 item 在块内不可用。这样做的原因是,如果块被子模板替换,则会出现一个未在块中定义或传递给上下文的变量。

从jinja 2.2开始,通过添加 scoped 块声明的修饰符::

{% for item in seq %}
    <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}

当覆盖块时, scoped 不必提供修饰符。

所需的数据块

数据块可以标记为 required 。它们必须在某个时刻被覆盖,但不一定被直接子模板覆盖。所需的块只能包含空格和注释,并且不能直接呈现。

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 %}

渲染 page.txtissue.txt 将筹集 TemplateRuntimeError 因为它们不会重写 body 阻止。渲染 bug_report.txt 将会成功,因为它确实重写了块。

当与 scoped vt.的. required 必须放置修饰符 after 限定范围的修饰符。以下是一些有说服力的例子:

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

模板对象

extendsinclude ,以及 import 可以采用模板对象而不是要加载的模板名称。这在某些高级情况下可能很有用,因为您可以先使用Python代码加载模板,然后将其传递给 render

if debug_mode:
    layout = env.get_template("debug_layout.html")
else:
    layout = env.get_template("layout.html")

user_detail = env.get_template("user/detail.html")
return user_detail.render(layout=layout)
{% extends layout %}

请注意如何 extends 与传递给的模板对象一起传递变量 render ,而不是字符串。

HTML逃逸

当从模板生成HTML时,变量总是存在包含影响结果HTML的字符的风险。有两种方法:

  1. 手动转义每个变量;或

  2. 默认情况下自动转义所有内容。

Jinja支持两者。使用什么取决于应用程序配置。默认配置不是自动转义;由于各种原因:

  • 转义除安全值之外的所有内容还意味着Jinja转义的变量不包括HTML(例如数字、布尔值),这可能会对性能造成巨大影响。

  • 有关变量安全性的信息非常脆弱。通过强制安全和不安全的值,返回值可能是双转义的HTML。

使用手动逃逸

如果启用了手动转义,则 your 如有必要,负责逃逸变量。怎么逃跑?如果你有一个变量 may 包括以下任何字符 (><&"SHOULD 除非变量包含格式良好且受信任的HTML,否则对其进行转义。通过管道将变量通过 |e 过滤器:

{{ user.username|e }}

使用自动转义

启用自动转义后,默认情况下,除了显式标记为安全的值外,所有内容都转义。变量和表达式可以在以下位置标记为安全:

  1. 应用程序的上下文字典 markupsafe.Markup

  2. 模板,带有 |safe 过滤器。

如果您标记为安全的字符串通过其他不理解该标记的Python代码传递,它可能会丢失。在到达模板之前,请注意何时将数据标记为安全的,以及如何处理这些数据。

如果某个值已转义但未标记为安全,则仍将自动转义并导致双转义字符。如果您知道您的数据已经是安全的但没有标记,请确保将其包装起来 Markup 或者使用 |safe 过滤器。

Jinja函数(宏, superself.BLOCKNAME )始终返回标记为安全的模板数据。

带有自动转义的模板中的字符串文字被认为是不安全的,因为本机Python字符串不安全。

控制结构清单

控制结构指的是控制程序流的所有东西——循环的条件(即if/elif/else),以及宏和块之类的东西。使用默认语法,控件结构出现在 {{% ... %}} 阻碍。

为了

按顺序循环每个项。例如,显示在变量中提供的用户列表 users ::

<h1>Members</h1>
<ul>
{% for user in users %}
  <li>{{ user.username|e }}</li>
{% endfor %}
</ul>

由于模板中的变量保留其对象属性,因此可以在类似 dict ::

<dl>
{% for key, value in my_dict.items() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

Python词典的显示顺序可能与您希望的不同。如果顺序很重要,请使用 |dictsort 过滤。

<dl>
{% for key, value in my_dict | dictsort %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

在for循环块内,可以访问一些特殊变量:

变量

描述

loop.index

循环的当前迭代。(1索引)

loop.index0

循环的当前迭代。(0索引)

loop.revindex

循环结束时的迭代次数(1个索引)

loop.revindex0

循环结束时的迭代次数(0个索引)

loop.first

如果第一次迭代为真。

loop.last

如果上次迭代为真。

loop.length

序列中的项数。

loop.cycle

在序列列表之间循环的辅助函数。请参阅下面的解释。

loop.depth

指示当前呈现在递归循环中的深度。从1级开始

loop.depth0

指示当前呈现在递归循环中的深度。从0级开始

loop.previtem

循环上一次迭代中的项。在第一次迭代期间未定义。

loop.nextitem

循环的以下迭代中的项。上次迭代时未定义。

loop.changed(*val)

如果以前使用其他值调用(或根本不调用),则为true。

在for循环中,可以通过使用 loop.cycle 帮手::

{% for row in rows %}
    <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}

自Jinja2.1以来,额外 cycle 存在允许循环未绑定循环的帮助程序。有关更多信息,请查看 全局函数列表 .

与Python不同,它不可能 breakcontinue 在一个循环中但是,您可以在迭代期间过滤序列,这允许您跳过项目。以下示例跳过所有隐藏的用户:

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

优势在于 loop 变量将正确计数;因此不计算未迭代的用户。

如果由于序列为空或筛选删除了序列中的所有项而没有进行迭代,则可以使用 else ::

<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% else %}
    <li><em>no users found</em></li>
{% endfor %}
</ul>

注意,在python中, else 每当相应的循环 没有 break . 因为Jinja环路不能 break 总之,一个稍微不同的行为 else 已选择关键字。

也可以递归地使用循环。如果您正在处理递归数据(如站点地图或RDFA),这将非常有用。要递归地使用循环,基本上必须添加 recursive 循环定义的修饰符并调用 loop 变量,新的iterable位于要递归的位置。

以下示例使用递归循环实现站点地图:

<ul class="sitemap">
{%- for item in sitemap recursive %}
    <li><a href="{{ item.href|e }}">{{ item.title }}</a>
    {%- if item.children -%}
        <ul class="submenu">{{ loop(item.children) }}</ul>
    {%- endif %}</li>
{%- endfor %}
</ul>

这个 loop 变量总是指最近的(最里面的)循环。如果我们有多个级别的循环,我们可以重新绑定变量 loop 通过写入 {{% set outer_loop = loop %}} 在循环之后,我们要递归使用。然后,我们可以用 {{{{ outer_loop(...) }}}}

请注意,循环中的赋值将在迭代结束时清除,并且不能超过循环范围。旧版本的Jinja有一个bug,在某些情况下,任务似乎可以工作。不支持此操作。看到了吗 作业 有关如何处理此问题的详细信息。

如果您只想检查某个值自上次迭代以来是否发生了更改,或者在下一次迭代中将发生更改,则可以使用 previtemnextitem ::

{% for value in values %}
    {% if loop.previtem is defined and value > loop.previtem %}
        The value just increased!
    {% endif %}
    {{ value }}
    {% if loop.nextitem is defined and loop.nextitem > value %}
        The value will increase even more!
    {% endif %}
{% endfor %}

如果您只关心值是否发生了变化,请使用 changed 更容易:

{% for entry in entries %}
    {% if loop.changed(entry.category) %}
        <h2>{{ entry.category }}</h2>
    {% endif %}
    <p>{{ entry.message }}</p>
{% endfor %}

如果

这个 if jinja中的语句与python if语句相当。在最简单的形式中,您可以使用它来测试是否定义了变量,不是空的,也不是假的:

{% if users %}
<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}

对于多个分支, elifelse 可以像在Python中那样使用。你可以使用更复杂的 表达 也有:

{% if kenny.sick %}
    Kenny is sick.
{% elif kenny.dead %}
    You killed Kenny!  You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}

如果还可以用作 inline expression 为了 loop filtering .

宏指令

宏可以与常规编程语言中的函数进行比较。将经常使用的习惯用法放入可重用的函数中以避免重复(“dry”)。

下面是呈现表单元素的宏的一个小示例:

{% 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

宏接受的参数名称的元组。

catch_kwargs

这是 true 如果宏接受额外的关键字参数(即:访问 kwargs 变量)。

catch_varargs

这是 true 如果宏接受额外的位置参数(即:访问 varargs 变量)。

caller

这是 true 如果宏访问 caller 变量,可以从 call 标签。

如果宏名以下划线开头,则不会导出宏名,也无法导入宏名。

由于作用域在JJJA中的工作方式,子模板中的宏不会覆盖父模板中的宏。下面的代码将输出“Layout”,而不是“Child”。

layout.txt
{% macro foo() %}LAYOUT{% endmacro %}
{% block body %}{% endblock %}
child.txt
{% extends 'layout.txt' %}
{% macro foo() %}CHILD{% endmacro %}
{% block body %}{{ foo() }}{% endblock %}

呼叫

在某些情况下,将宏传递给另一个宏可能很有用。为此,您可以使用 call 块。下面的示例显示了一个宏,它利用了调用功能以及如何使用它:

{% 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 %}

也可以将参数传递回调用块。这使得它可以用作循环的替换。一般来说,调用块的工作方式与没有名称的宏完全相同。

以下是如何将调用块与参数一起使用的示例:

{% macro dump_users(users) -%}
    <ul>
    {%- for user in users %}
        <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
    {%- endfor %}
    </ul>
{%- endmacro %}

{% call(user) dump_users(list_of_user) %}
    <dl>
        <dt>Realname</dt>
        <dd>{{ user.realname|e }}</dd>
        <dt>Description</dt>
        <dd>{{ user.description }}</dd>
    </dl>
{% endcall %}

过滤器

过滤器部分允许您对模板数据块应用常规的Jinja过滤器。把代码包装在特殊的 filter 章节:

{% filter upper %}
    This text becomes uppercase
{% endfilter %}

可以这样调用接受参数的筛选器::

{% filter center(100) %}Center this{% endfilter %}

作业

在代码块内,还可以为变量赋值。顶层(块、宏或循环之外)的工作分配与顶层宏一样从模板中导出,并且可以由其他模板导入。

工作分配使用 set 标记并可以有多个目标:

{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}

范围界定行为

请记住,不可能在一个块内设置变量并让它们显示在块外。这也适用于循环。唯一的例外是不引入范围的if语句。因此,以下模板不会执行您可能期望的操作:

{% set iterated = false %}
{% for item in seq %}
    {{ item }}
    {% set iterated = true %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %}

使用jinja语法是不可能做到这一点的。相反,使用循环else块或特殊的 loop 变量::

{% for item in seq %}
    {{ item }}
{% else %}
    did not iterate
{% endfor %}

从2.10版开始,可以使用允许跨作用域传播更改的命名空间对象来处理更复杂的用例:

{% set ns = namespace(found=false) %}
{% for item in items %}
    {% if item.check_something() %}
        {% set ns.found = true %}
    {% endif %}
    * {{ item.title }}
{% endfor %}
Found item having something: {{ ns.found }}

请注意 obj.attr 符号表示法 set 标记只允许用于命名空间对象;尝试在任何其他对象上分配属性将引发异常。

Changelog

在 2.10 版本加入: 添加了对命名空间对象的支持

阻止分配

Changelog

在 2.8 版本加入.

从Jinja2.8开始,还可以使用块分配将块的内容捕获到变量名中。在某些情况下,这可以作为宏的替代方法。在这种情况下,不使用等号和值,只需编写变量名,然后编写所有内容,直到 {{% endset %}} 被捕获。

例子::

{% set navigation %}
    <li><a href="/">Index</a>
    <li><a href="/downloads">Downloads</a>
{% endset %}

这个 navigation 然后变量包含导航HTML源代码。

Changelog

在 2.10 版本发生变更.

从Jinja 2.10开始,块分配支持过滤器。

例子::

{% set reply | wordwrap %}
    You wrote:
    {{ message }}
{% endset %}

延伸

这个 extends 标记可用于从一个模板扩展到另一个模板。你可以有多个 extends 文件中的标记,但一次只能执行其中一个标记。

参见关于 模板继承 上面。

阻碍

块用于继承,同时充当占位符和替换。它们详细记录在 模板继承 部分。

包括

这个 include 标记呈现另一个模板并将结果输出到当前模板。

{% include 'header.html' %}
Body goes here.
{% include 'footer.html' %}

默认情况下,包含的模板可以访问当前模板的上下文。使用 without context 改为使用单独的上下文。 with context 也是有效的,但这是默认行为。看见 导入上下文行为

包含的模板可以 extend 另一个模板和该模板中的替代块。但是,当前模板不能替代包含的模板输出的任何块。

使用 ignore missing 如果模板不存在,则忽略该语句。必须把它放在 before 情景可见性声明。

{% include "sidebar.html" without context %}
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}

如果给出了模板列表,将按顺序尝试每个模板,直到其中一个模板不会丢失。此命令可与 ignore missing 如果不存在任何模板,则忽略。

{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}

还可以将具有模板名称或模板对象的变量传递给语句。

输入

Jinja支持将常用代码放入宏中。这些宏可以进入不同的模板并从中导入。这类似于Python中的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 %}

访问模板变量和宏的最简单和最灵活的方法是将整个模板模块导入到变量中。这样,您就可以访问以下属性:

{% 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>

以一个或多个下划线开头的宏和变量是私有的,无法导入。

Changelog

在 2.4 版本发生变更: 如果模板对象已传递到模板上下文,则可以从该对象导入。

导入上下文行为

默认情况下,所包含的模板将传递到当前上下文,而导入的模板则不传递。这样做的原因是,与include不同,导入被缓存;因为导入通常被用作保存宏的模块。

此行为可以显式更改:通过添加 with contextwithout context 对于import/include指令,可以将当前上下文传递到模板,并自动禁用缓存。

以下是两个例子:

{% from 'forms.html' import input with context %}
{% include 'header.html' without context %}

注意

在Jinja2.0中,传递给包含模板的上下文不包括模板中定义的变量。事实上,这不起作用:

{% for box in boxes %}
    {% include "render_box.html" %}
{% endfor %}

包含的模板 render_box.htmlnot 能够访问 box 在Jinja2。从Jinja 2.1开始, render_box.html is 能够做到这一点。

表达

Jinja允许在任何地方使用基本的表达方式。这些方法与普通的python非常相似;即使您不使用python,也应该对它感到舒适。

直接常量

最简单的表达式形式是文本。文本是Python对象(如字符串和数字)的表示形式。存在以下文字:

"Hello World"

两个双引号或单引号之间的所有内容都是字符串。当您需要模板中的字符串时(例如,作为函数调用和筛选器的参数,或者只是为了扩展或包含模板),它们都非常有用。

42 / 123_456

整数是不带小数部分的整数。“字符”可用于分隔组以确保易读性。

42.23 / 42.1e2 / 123_456.789

浮点数可以用“.”作为小数点。它们也可以用科学记数法写成,用大写或小写字母“e”表示指数部分。“字符”可用于分隔组以确保易读性,但不能用于指数部分。

['list', 'of', 'objects']

两个括号之间的所有内容都是一个列表。列表对于存储要迭代的顺序数据很有用。例如,可以使用for(和with)for循环的列表和元组轻松创建链接列表:

<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
                         ('downloads.html', 'Downloads')] %}
    <li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>
('tuple', 'of', 'values')

元组类似于无法修改的列表(“不可变”)。如果一个元组只有一个项,它必须后跟一个逗号。 (('1-tuple',) )元组通常用于表示两个或多个元素的项。有关详细信息,请参阅上面的列表示例。

{'dict': 'of', 'key': 'and', 'value': 'pairs'}

python中的dict是一种组合键和值的结构。键必须唯一,并且始终只有一个值。口述在模板中很少使用;它们在一些罕见的情况下很有用,例如 xmlattr() 过滤器。

true / false

true 总是正确的而且 false 总是假的。

注意

特殊常数 truefalsenone 确实是小写的。因为这在过去引起了混乱, (True 用于扩展到被认为是错误的未定义变量),现在这三个变量都可以用标题大小写 (TrueFalseNone )但是,为了一致性,(所有的Jinja标识符都是小写的),您应该使用小写版本。

数学

Jinja允许您使用值进行计算。这在模板中很少有用,但为了完整性而存在。支持以下运算符:

+

将两个对象添加到一起。通常,对象都是数字,但如果两者都是字符串或列表,则可以这样连接它们。但是,这不是连接字符串的首选方法!对于字符串连接,请查看 ~ 运算符。 {{{{ 1 + 1 }}}}2 .

-

从第一个数中减去第二个数。 {{{{ 3 - 2 }}}}1 .

/

把两个数字分开。返回值将是一个浮点数。 {{{{ 1 / 2 }}}}{{{{ 0.5 }}}} .

//

将两个数字相除并返回截断的整数结果。 {{{{ 20 // 7 }}}}2 .

%

计算整数除法的余数。 {{{{ 11 % 7 }}}}4 .

*

将左操作数与右操作数相乘。 {{{{ 2 * 2 }}}} 会回来 4 . 这也可以用于多次重复字符串。 {{{{ '=' * 80 }}}} 将打印一个80等号的条。

**

将左操作数提升到右操作数的幂。 {{ 2**3 }} 会回来 8

与Python不同,链式威力是从左到右求值的。 {{ 3**3**3 }} 被评估为 (3**3)**3 在Jinja,但会被评估为 3**(3**3) 在Python中。在JJJA中使用圆括号来明确您想要的顺序。通常,更可取的做法是在Python中进行扩展数学运算,然后将结果传递给 render 而不是在模板中这样做。

如果有可能引入升级路径,将来可能会更改此行为以匹配Python。

比较

==

比较两个对象是否相等。

!=

比较两个对象的不等式。

>

true 如果左侧大于右侧。

>=

true 如果左侧大于或等于右侧。

<

true 如果左侧低于右侧。

<=

true 如果左侧低于或等于右侧。

逻辑

为了 if 声明, for 过滤,以及 if 表达式,组合多个表达式可能很有用:

and

如果左操作数和右操作数为真,则返回真。

or

如果左操作数或右操作数为真,则返回真。

not

否定一个陈述(见下文)。

(expr)

括号将表达式分组。

注意

这个 isin 运算符也支持使用中缀表示法求反: foo is not barfoo not in bar 而不是 not foo is barnot foo in bar . 所有其他表达式都需要前缀表示法: not (foo and bar).

其他经营者

以下运算符非常有用,但不适用于其他两个类别:

in

执行序列/映射控制测试。如果左操作数包含在右操作数中,则返回true。 {{{{ 1 in [1, 2, 3] }}}} 例如,将返回true。

is

执行一个 test .

| (竖线、竖线)

应用A filter .

~ (Tilde)

将所有操作数转换为字符串并将它们连接起来。

{{{{ "Hello " ~ name ~ "!" }}}} 将返回(假设 name 设置为 'John'Hello John! .

()

呼叫可呼叫: {{{{ post.render() }}}} . 在圆括号内,可以使用位置参数和关键字参数,如在python中:

{{{{ post.render(user, full=true) }}}} .

. / []

获取对象的属性。(见 变量

if表达式

也可以使用内联 if 表达。这些在某些情况下是有用的。例如,如果定义了变量,则可以使用此从一个模板扩展,否则从默认布局模板扩展:

{% extends layout_template if layout_template is defined else 'default.html' %}

一般的语法是 <do something> if <something is true> else <do something else> .

这个 else 零件是可选的。如果未提供,else块隐式计算为 Undefined 对象(不管什么 undefined 环境中设置为:

{{ "[{}]".format(page.title) if page.title }}

Python方法

您还可以使用在变量类型上定义的任何方法。从方法调用返回的值用作表达式的值。下面是一个使用在字符串上定义的方法的示例(其中 page.title 是一个字符串):

{{ page.title.capitalize() }}

这适用于用户定义类型上的方法。例如,if变量 f 类型的 Foo 有方法吗 bar 在其上定义,可以执行以下操作:

{{ f.bar(value) }}

运算符方法也按预期工作。例如, % 为字符串实现printf样式:

{{ "Hello, %s!" % name }}

虽然你应该更喜欢 .format 方法(在呈现模板的上下文中有点做作):

{{ "Hello, {}!".format(name) }}

内置过滤器列表

abs()

forceescape()

map()

select()

unique()

attr()

format()

max()

selectattr()

upper()

batch()

groupby()

min()

slice()

urlencode()

capitalize()

indent()

pprint()

sort()

urlize()

center()

int()

random()

string()

wordcount()

default()

items()

reject()

striptags()

wordwrap()

dictsort()

join()

rejectattr()

sum()

xmlattr()

escape()

last()

replace()

title()

filesizeformat()

length()

reverse()

tojson()

first()

list()

round()

trim()

float()

lower()

safe()

truncate()

jinja-filters.abs(x, /)

返回参数的绝对值。

jinja-filters.attr(obj: Any, name: str) jinja2.runtime.Undefined | Any

获取对象的属性。 foo|attr("bar") 工作原理类似 foo.bar 只是始终返回一个属性,而不查找项。

Notes on subscriptions 了解更多详细信息。

jinja-filters.batch(value: 't.Iterable[V]', linecount: int, fill_with: 't.Optional[V]' = None) 't.Iterator[t.List[V]]'

批处理项目的筛选器。它的工作原理很像 slice 正好相反。它返回具有给定项数的列表列表。如果提供第二个参数,则用于填充缺少的项。请参见以下示例:

<table>
{%- for row in items|batch(3, '&nbsp;') %}
  <tr>
  {%- for column in row %}
    <td>{{ column }}</td>
  {%- endfor %}
  </tr>
{%- endfor %}
</table>
jinja-filters.capitalize(s: str) str

将值大写。第一个字符将为大写,其他所有字符均为小写。

jinja-filters.center(value: str, width: int = 80) str

将给定宽度的字段中的值居中。

jinja-filters.default(value: V, default_value: V = '', boolean: bool = False) V

如果该值未定义,则返回传递的默认值,否则返回变量的值:

{{ my_variable|default('my_variable is not defined') }}

这将输出 my_variable 如果变量已定义,否则 'my_variable is not defined' . 如果要对值为false的变量使用默认值,则必须将第二个参数设置为 true

{{ ''|default('the string was empty', true) }}
Changelog

在 2.11 版本发生变更: 现在可以配置 Environment 具有 ChainableUndefined 使 default 过滤器处理嵌套元素和属性,这些元素和属性在链中可能包含未定义的值,而不会获得 UndefinedError .

别名:

d

jinja-filters.dictsort(value: Mapping[K, V], case_sensitive: bool = False, by: 'te.Literal["key", "value"]' = 'key', reverse: bool = False) List[Tuple[K, V]]

对字典进行排序并生成(键、值)对。Python词典的显示顺序可能与您希望的不同,因此请先对它们进行排序。

{% for key, value in mydict|dictsort %}
    sort the dict by key, case insensitive

{% for key, value in mydict|dictsort(reverse=true) %}
    sort the dict by key, case insensitive, reverse order

{% for key, value in mydict|dictsort(true) %}
    sort the dict by key, case sensitive

{% for key, value in mydict|dictsort(false, 'value') %}
    sort the dict by value, case insensitive
jinja-filters.escape(value)

替换字符 &<>' ,以及 " 在具有HTML安全序列的字符串中。如果需要在HTML中显示可能包含此类字符的文本,请使用此选项。

如果该对象具有 __html__ 方法,则会调用该方法,并且假定返回值对于HTML已经是安全的。

参数:

s -- 要转换为字符串并转义的对象。

返回:

A Markup 包含转义文本的字符串。

别名:

e

jinja-filters.filesizeformat(value: str | float | int, binary: bool = False) str

将值格式化为“人类可读”的文件大小(即13 KB、4.1 MB、102字节等)。如果第二个参数设置为,则使用默认的十进制前缀(mega、giga等)。 True 使用二进制前缀(mebi、gibi)。

jinja-filters.first(seq: 't.Iterable[V]') 't.Union[V, Undefined]'

返回序列的第一项。

jinja-filters.float(value: Any, default: float = 0.0) float

将该值转换为浮点数。如果转换不起作用,它将返回 0.0 . 可以使用第一个参数覆盖此默认值。

jinja-filters.forceescape(value: 't.Union[str, HasHTML]') markupsafe.Markup

强制HTML转义。这可能会使转义变量加倍。

jinja-filters.format(value: str, *args: Any, **kwargs: Any) str

将给定值应用于 printf-style 格式化字符串,例如 string % values .

{{ "%s, %s!"|format(greeting, name) }}
Hello, World!

在大多数情况下,使用 % 操作员或 str.format() .

{{ "%s, %s!" % (greeting, name) }}
{{ "{}, {}!".format(greeting, name) }}
jinja-filters.groupby(value: 't.Iterable[V]', attribute: str | int, default: Any | None = None, case_sensitive: bool = False) 't.List[_GroupTuple]'

使用Python的 itertools.groupby() . 属性可以对嵌套访问使用点表示法,例如 "address.city" . 不像Python的 groupby ,首先对值进行排序,因此每个唯一值只返回一个组。

例如,列表 User 对象与A city 属性可以分组呈现。在这个例子中, grouper 指的是 city 组的值。

<ul>{% for city, items in users|groupby("city") %}
  <li>{{ city }}
    <ul>{% for user in items %}
      <li>{{ user.name }}
    {% endfor %}</ul>
  </li>
{% endfor %}</ul>

groupby 产生的命名成对 (grouper, list) ,它可以代替上面的元组解包。 grouper 属性的值,并且 list 是具有该值的项。

<ul>{% for group in users|groupby("city") %}
  <li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>

您可以指定 default 当列表中的对象没有给定属性时使用的值。

<ul>{% for city, items in users|groupby("city", default="NY") %}
  <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>

就像 sort() 默认情况下,筛选、排序和分组不区分大小写。这个 key 对于每个组,将具有该组值中第一项的大小写。例如,如果用户列表包含城市 ["CA", "NY", "ca"] ,“CA”组将有两个值。这可以通过传递以下命令来禁用 case_sensitive=True

在 3.1 版本发生变更: 添加了 case_sensitive 参数。默认情况下,排序和分组不区分大小写,与执行比较的其他筛选器匹配。

Changelog

在 3.0 版本发生变更: 增加了 default 参数。

在 2.6 版本发生变更: 该属性支持嵌套访问的点表示法。

jinja-filters.indent(s: str, width: int | str = 4, first: bool = False, blank: bool = False) str

返回字符串的副本,每行缩进4个空格。默认情况下,首行和空行不缩进。

参数:
  • width -- 要缩进的空格或字符串的数量。

  • first -- 不要跳过首行缩进。

  • blank -- 不要跳过空行缩进。

Changelog

在 3.0 版本发生变更: width 可以是字符串。

在 2.10 版本发生变更: 默认情况下,空行不缩进。

重命名 indentfirst 参数 first .

jinja-filters.int(value: Any, default: int = 0, base: int = 10) int

将该值转换为整数。如果转换不起作用,它将返回 0 . 可以使用第一个参数覆盖此默认值。您还可以重写第二个参数中的默认基数(10),该参数用前缀(如0b、0o和0x)分别处理基数2、8和16的输入。十进制数和非字符串值的基数被忽略。

jinja-filters.items(value: Mapping[K, V] | jinja2.runtime.Undefined) Iterator[Tuple[K, V]]

返回一个迭代器 (key, value) 映射的项。

x|items 与之相同 x.items() ,除非符合以下条件 x 如果未定义,则返回空迭代器。

如果希望使用另一种编程语言的JJJA实现呈现模板,则此筛选器非常有用 .items() 方法的映射类型。

<dl>
{% for key, value in my_dict|items %}
    <dt>{{ key }}
    <dd>{{ value }}
{% endfor %}
</dl>

在 3.1 版本加入.

jinja-filters.join(value: Iterable, d: str = '', attribute: str | int | NoneType = None) str

返回一个字符串,该字符串是序列中字符串的串联。元素之间的分隔符默认为空字符串,您可以使用可选参数定义它:

{{ [1, 2, 3]|join('|') }}
    -> 1|2|3

{{ [1, 2, 3]|join }}
    -> 123

也可以连接对象的某些属性:

{{ users|join(', ', attribute='username') }}
Changelog

在 2.6 版本加入: 这个 attribute 已添加参数。

jinja-filters.last(seq: 't.Reversible[V]') 't.Union[V, Undefined]'

返回序列的最后一项。

注意:不适用于发电机。您可能需要显式地将其转换为列表:

{{ data | selectattr('name', '==', 'Jinja') | list | last }}
jinja-filters.length(obj, /)

返回容器中的项目数。

别名:

count

jinja-filters.list(value: 't.Iterable[V]') 't.List[V]'

将值转换为列表。如果是字符串,则返回的列表将是字符列表。

jinja-filters.lower(s: str) str

将值转换为小写。

jinja-filters.map(value: Iterable, *args: Any, **kwargs: Any) Iterable

对对象序列应用筛选器或查找属性。这在处理对象列表时很有用,但实际上您只对对象的某个值感兴趣。

基本用法是对属性进行映射。假设您有一个用户列表,但您只对一个用户名列表感兴趣:

Users on this page: {{ users|map(attribute='username')|join(', ') }}

您可以指定 default 当列表中的对象没有给定属性时使用的值。

{{ users|map(attribute="username", default="Anonymous")|join(", ") }}

或者,您可以让它通过在后面传递过滤器的名称和参数来调用过滤器。一个很好的例子是对序列应用文本转换过滤器:

Users on this page: {{ titles|map('lower')|join(', ') }}

与生成器理解类似,例如:

(u.username for u in users)
(getattr(u, "username", "Anonymous") for u in users)
(do_lower(x) for x in titles)
Changelog

在 2.11.0 版本发生变更: 增加了 default 参数。

在 2.7 版本加入.

jinja-filters.max(value: 't.Iterable[V]', case_sensitive: bool = False, attribute: str | int | NoneType = None) 't.Union[V, Undefined]'

返回序列中最大的项。

{{ [1, 2, 3]|max }}
    -> 3
参数:
  • case_sensitive -- 将大小写字符串视为不同的字符串。

  • attribute -- 获取具有此属性最大值的对象。

jinja-filters.min(value: 't.Iterable[V]', case_sensitive: bool = False, attribute: str | int | NoneType = None) 't.Union[V, Undefined]'

返回序列中最小的项。

{{ [1, 2, 3]|min }}
    -> 1
参数:
  • case_sensitive -- 将大小写字符串视为不同的字符串。

  • attribute -- 获取具有此属性最小值的对象。

jinja-filters.pprint(value: Any) str

漂亮的打印变量。用于调试。

jinja-filters.random(seq: 't.Sequence[V]') 't.Union[V, Undefined]'

从序列中返回随机项。

jinja-filters.reject(value: 't.Iterable[V]', *args: Any, **kwargs: Any) 't.Iterator[V]'

通过对每个对象应用一个测试来筛选一系列对象,并在测试成功后拒绝这些对象。

如果未指定测试,则每个对象都将作为布尔值进行计算。

示例用法:

{{ numbers|reject("odd") }}

与生成器理解类似,例如:

(n for n in numbers if not test_odd(n))
Changelog

在 2.7 版本加入.

jinja-filters.rejectattr(value: 't.Iterable[V]', *args: Any, **kwargs: Any) 't.Iterator[V]'

通过对每个对象的指定属性应用测试,并在测试成功后拒绝对象,来筛选对象序列。

如果未指定测试,则属性的值将作为布尔值进行计算。

{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}

与生成器理解类似,例如:

(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))
Changelog

在 2.7 版本加入.

jinja-filters.replace(s: str, old: str, new: str, count: int | None = None) str

返回该值的副本,其中所有出现的子字符串都替换为新的子字符串。第一个参数是应该替换的子字符串,第二个参数是替换字符串。如果可选的第三个参数 count 只有第一个 count 出现项被替换:

{{ "Hello World"|replace("Hello", "Goodbye") }}
    -> Goodbye World

{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
    -> d'oh, d'oh, aaargh
jinja-filters.reverse(value: str | Iterable[V]) str | Iterable[V]

反转对象,或者返回一个迭代程序,该迭代程序以相反的方式对其进行迭代。

jinja-filters.round(value: float, precision: int = 0, method: 'te.Literal["common", "ceil", "floor"]' = 'common') float

将数字四舍五入到给定的精度。第一个参数指定精度(默认为 0 ,第二种取整方法:

  • 'common' 向上或向下舍入

  • 'ceil' 总是向上搜索

  • 'floor' 总是向下舍入

如果不指定方法 'common' 使用。

{{ 42.55|round }}
    -> 43.0
{{ 42.55|round(1, 'floor') }}
    -> 42.5

请注意,即使舍入到0精度,也会返回一个浮点。如果你需要一个真正的整数,通过管道 int

{{ 42.55|round|int }}
    -> 43
jinja-filters.safe(value: str) markupsafe.Markup

将该值标记为安全,这意味着在启用自动转义的环境中,不会转义该变量。

jinja-filters.select(value: 't.Iterable[V]', *args: Any, **kwargs: Any) 't.Iterator[V]'

通过对每个对象应用测试来筛选一系列对象,并且只在测试成功后选择对象。

如果未指定测试,则每个对象都将作为布尔值进行计算。

示例用法:

{{ numbers|select("odd") }}
{{ numbers|select("odd") }}
{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }}
{{ strings|select("equalto", "mystring") }}

与生成器理解类似,例如:

(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))
Changelog

在 2.7 版本加入.

jinja-filters.selectattr(value: 't.Iterable[V]', *args: Any, **kwargs: Any) 't.Iterator[V]'

通过对每个对象的指定属性应用测试来筛选一系列对象,并且只选择测试成功的对象。

如果未指定测试,则属性的值将作为布尔值进行计算。

示例用法:

{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}

与生成器理解类似,例如:

(u for user in users if user.is_active)
(u for user in users if test_none(user.email))
Changelog

在 2.7 版本加入.

jinja-filters.slice(value: 't.Collection[V]', slices: int, fill_with: 't.Optional[V]' = None) 't.Iterator[t.List[V]]'

切片迭代器并返回包含这些项的列表列表。如果要创建一个包含三个代表列的ul标记的DIV,则非常有用:

<div class="columnwrapper">
  {%- for column in items|slice(3) %}
    <ul class="column-{{ loop.index }}">
    {%- for item in column %}
      <li>{{ item }}</li>
    {%- endfor %}
    </ul>
  {%- endfor %}
</div>

如果您给它传递第二个参数,它将用于在上一次迭代中填充缺少的值。

jinja-filters.sort(value: 't.Iterable[V]', reverse: bool = False, case_sensitive: bool = False, attribute: str | int | NoneType = None) 't.List[V]'

使用Python的 sorted() .

{% for city in cities|sort %}
    ...
{% endfor %}
参数:
  • reverse -- 降序排序而不是升序排序。

  • case_sensitive -- 排序字符串时,请分别对大小写进行排序。

  • attribute -- 当对对象或指令进行排序时,要按其排序的属性或键。可以用点表示法 "address.city" . 可以是以下属性的列表 "age,name" .

排序是稳定的,它不会改变比较相等的元素的相对顺序。这使得可以根据不同的属性和顺序进行排序。

{% for user in users|sort(attribute="name")
    |sort(reverse=true, attribute="age") %}
    ...
{% endfor %}

当所有属性的方向相同时,作为链接的快捷方式,请传递一个逗号分隔的属性列表。

{% for user in users|sort(attribute="age,name") %}
    ...
{% endfor %}
Changelog

在 2.11.0 版本发生变更: 这个 attribute 参数可以是逗号分隔的属性列表,例如。 "age,name" .

在 2.6 版本发生变更: 这个 attribute 已添加参数。

jinja-filters.string(value)

如果对象尚未转换为字符串,请将其转换为字符串。这将保留一个 Markup 字符串,而不是将其转换回基本字符串,因此它仍将被标记为安全,并且不会再次转义。

>>> value = escape("<User 1>")
>>> value
Markup('&lt;User 1&gt;')
>>> escape(str(value))
Markup('&amp;lt;User 1&amp;gt;')
>>> escape(soft_str(value))
Markup('&lt;User 1&gt;')
jinja-filters.striptags(value: 't.Union[str, HasHTML]') str

去掉sgml/xml标记并用一个空格替换相邻的空白。

jinja-filters.sum(iterable: 't.Iterable[V]', attribute: str | int | NoneType = None, start: V = 0) V

返回数字序列与参数“start”(默认值为0)的值之和。当序列为空时,它返回Start。

也可以只总结某些属性:

Total: {{ items|sum(attribute='price') }}
Changelog

在 2.6 版本发生变更: 这个 attribute 添加了参数以允许对属性进行求和。也就是 start 参数被移到右侧。

jinja-filters.title(s: str) str

返回值的基于标题的版本。也就是说,单词将以大写字母开头,其余所有字符都是小写。

jinja-filters.tojson(value: Any, indent: int | None = None) markupsafe.Markup

将对象序列化为JSON字符串,并将其标记为可以在HTML中安全呈现。此过滤仅用于Html文档。

返回的字符串在HTML文档中呈现是安全的,并且 <script> 标签。例外是在用双引号引起来的HTML属性中;可以使用单引号,也可以使用 |forceescape 过滤。

参数:
  • value -- 要序列化为JSON的对象。

  • indent -- 这个 indent 传递给的参数 dumps ,用于漂亮地打印价值。

Changelog

在 2.9 版本加入.

jinja-filters.trim(value: str, chars: str | None = None) str

去掉前导字符和尾随字符,默认为空白。

jinja-filters.truncate(s: str, length: int = 255, killwords: bool = False, end: str = '...', leeway: int | None = None) str

返回字符串的截断副本。长度由第一个参数指定,默认为 255 . 如果第二个参数是 true 过滤器将剪切文本的长度。否则,它将丢弃最后一个单词。如果文本被截断,它将附加省略号 ("..." )如果你想要一个不同的省略号 "..." 您可以使用第三个参数指定它。仅超过第四个参数中给定的公差范围长度的字符串将不会被截断。

{{ "foo bar baz qux"|truncate(9) }}
    -> "foo..."
{{ "foo bar baz qux"|truncate(9, True) }}
    -> "foo ba..."
{{ "foo bar baz qux"|truncate(11) }}
    -> "foo bar baz qux"
{{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
    -> "foo bar..."

新的Jinja版本的默认余地是5,以前是0,但可以全局重新配置。

jinja-filters.unique(value: 't.Iterable[V]', case_sensitive: bool = False, attribute: str | int | NoneType = None) 't.Iterator[V]'

返回给定iterable中唯一项的列表。

{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
    -> ['foo', 'bar', 'foobar']

唯一项的生成顺序与传递给筛选器的iterable中第一次出现的顺序相同。

参数:
  • case_sensitive -- 将大小写字符串视为不同的字符串。

  • attribute -- 为此属性筛选具有唯一值的对象。

jinja-filters.upper(s: str) str

将值转换为大写。

jinja-filters.urlencode(value: str | Mapping[str, Any] | Iterable[Tuple[str, Any]]) str

引用数据以便在URL路径或使用UTF-8的查询中使用。

基本包装 urllib.parse.quote() 如果给了一个字符串,或者 urllib.parse.urlencode() 为了一个口述或一个可写的。

参数:

value -- 要引用的数据。字符串将被直接引用。口述 (key, value) 对将作为查询字符串联接。

当给定字符串时,“/”不加引号。HTTP服务器在路径中等价地处理“/”和“%2F”。如果需要引用斜杠,请使用 |replace("/", "%2F") 过滤器。

Changelog

在 2.7 版本加入.

jinja-filters.urlize(value: str, trim_url_limit: int | None = None, nofollow: bool = False, target: str | None = None, rel: str | None = None, extra_schemes: Iterable[str] | None = None) str

将文本中的URL转换为可点击的链接。

在某些情况下,这可能无法识别链接。通常,更全面的格式化程序(如Markdown库)是更好的选择。

工作于 http://https://www.mailto: 和电子邮件地址。带有尾随标点符号(句点、逗号、右括号)和前导标点符号(左括号)的链接将被识别,但不包括标点符号。不识别包括报头字段的电子邮件地址(例如, mailto:address@example.com?cc=copy@example.com )。

参数:
  • value -- 包含要链接的URL的原始文本。

  • trim_url_limit -- 将显示的URL值缩短到此长度。

  • nofollow -- 添加 rel=nofollow 属性添加到链接。

  • target -- 添加 target 属性添加到链接。

  • rel -- 添加 rel 属性添加到链接。

  • extra_schemes -- 除了默认行为之外,还可以识别以这些方案开头的URL。默认为 env.policies["urlize.extra_schemes"] ,它默认为没有额外的方案。

Changelog

在 3.0 版本发生变更: 这个 extra_schemes 参数已添加。

在 3.0 版本发生变更: 生成 https:// 没有方案的URL链接。

在 3.0 版本发生变更: 解析规则已更新。识别电子邮件地址,无论是否使用 mailto: 计划。验证IP地址。在更多情况下忽略圆括号和方括号。

在 2.8 版本发生变更: 这个 target 参数已添加。

jinja-filters.wordcount(s: str) int

数一数那个字符串中的单词。

jinja-filters.wordwrap(s: str, width: int = 79, break_long_words: bool = True, wrapstring: str | None = None, break_on_hyphens: bool = True) str

将字符串按给定宽度换行。现有换行符被视为要单独包装的段落。

参数:
  • s -- 要换行的原始文本。

  • width -- 包装线的最大长度。

  • break_long_words -- 如果一个单词比 width ,把它分开。

  • break_on_hyphens -- 如果一个单词包含连字符,它可以被拆分成多行。

  • wrapstring -- 连接每个换行符的字符串。默认为 Environment.newline_sequence .

Changelog

在 2.11 版本发生变更: 现有换行符被视为单独包装的段落。

在 2.11 版本发生变更: 增加了 break_on_hyphens 参数。

在 2.7 版本发生变更: 增加了 wrapstring 参数。

jinja-filters.xmlattr(d: Mapping[str, Any], autospace: bool = True) str

基于dict中的项创建sgml/xml属性字符串。所有值都不是 none 也不 undefined 自动转义:

<ul{{ {'class': 'my_list', 'missing': none,
        'id': 'list-%d'|format(variable)}|xmlattr }}>
...
</ul>

结果是这样的:

<ul class="my_list" id="list-42">
...
</ul>

如您所见,如果过滤器返回某些内容,除非第二个参数为false,否则它会自动在项目前面预留一个空格。

内置测试列表

boolean()

even()

in()

mapping()

sequence()

callable()

false()

integer()

ne()

string()

defined()

filter()

iterable()

none()

test()

divisibleby()

float()

le()

number()

true()

eq()

ge()

lower()

odd()

undefined()

escaped()

gt()

lt()

sameas()

upper()

jinja-tests.boolean(value: Any) bool

如果对象是布尔值,则返回true。

Changelog

在 2.11 版本加入.

jinja-tests.callable(obj, /)

返回对象是否可调用(即某种函数)。

请注意,类是可调用的,使用uuu call_uu()方法的类的实例也是可调用的。

jinja-tests.defined(value: Any) bool

如果定义了变量,则返回true:

{% if variable is defined %}
    value of variable: {{ variable }}
{% else %}
    variable is not defined
{% endif %}

default() 筛选以获取设置未定义变量的简单方法。

jinja-tests.divisibleby(value: int, num: int) bool

检查变量是否可被数字整除。

jinja-tests.eq(a, b, /)

与a==b相同。

别名:

==, equalto

jinja-tests.escaped(value: Any) bool

检查值是否已转义。

jinja-tests.even(value: int) bool

如果变量为偶数,则返回true。

jinja-tests.false(value: Any) bool

如果对象为False,则返回true。

Changelog

在 2.11 版本加入.

jinja-tests.filter(value: str) bool

按名称检查是否存在过滤。如果可能有过滤可选,则非常有用。

{% if 'markdown' is filter %}
    {{ value | markdown }}
{% else %}
    {{ value }}
{% endif %}
Changelog

在 3.0 版本加入.

jinja-tests.float(value: Any) bool

如果对象是float,则返回true。

Changelog

在 2.11 版本加入.

jinja-tests.ge(a, b, /)

与a>=b相同。

别名:

>=

jinja-tests.gt(a, b, /)

与a>b相同。

别名:

>, greaterthan

jinja-tests.in(value: Any, seq: Container) bool

检查值是否在seq中。

Changelog

在 2.10 版本加入.

jinja-tests.integer(value: Any) bool

如果对象是整数,则返回true。

Changelog

在 2.11 版本加入.

jinja-tests.iterable(value: Any) bool

检查是否可以迭代对象。

jinja-tests.le(a, b, /)

与a<=b相同。

别名:

<=

jinja-tests.lower(value: str) bool

如果变量的基数较低,则返回true。

jinja-tests.lt(a, b, /)

与a<b相同。

别名:

<, lessthan

jinja-tests.mapping(value: Any) bool

如果对象是映射(dict等),则返回true。

Changelog

在 2.6 版本加入.

jinja-tests.ne(a, b, /)

和a一样!=b。

别名:

!=

jinja-tests.none(value: Any) bool

如果变量为“无”,则返回“真”。

jinja-tests.number(value: Any) bool

如果变量是数字,则返回true。

jinja-tests.odd(value: int) bool

如果变量是奇数,则返回true。

jinja-tests.sameas(value: Any, other: Any) bool

检查一个对象是否指向与另一个对象相同的内存地址:

{% if foo.attribute is sameas false %}
    the foo attribute really is the `False` singleton
{% endif %}
jinja-tests.sequence(value: Any) bool

如果变量是序列,则返回true。序列是不可迭代的变量。

jinja-tests.string(value: Any) bool

如果对象是字符串,则返回true。

jinja-tests.test(value: str) bool

按名称检查是否存在测试。如果测试可能是可选的,则非常有用。

{% if 'loud' is test %}
    {% if value is loud %}
        {{ value|upper }}
    {% else %}
        {{ value|lower }}
    {% endif %}
{% else %}
    {{ value }}
{% endif %}
Changelog

在 3.0 版本加入.

jinja-tests.true(value: Any) bool

如果对象为true,则返回true。

Changelog

在 2.11 版本加入.

jinja-tests.undefined(value: Any) bool

喜欢 defined() 但反过来说。

jinja-tests.upper(value: str) bool

如果变量为大写,则返回true。

全局函数列表

默认情况下,以下函数在全局范围内可用:

jinja-globals.range([start, ]stop[, step])

返回包含整数算术级数的列表。 range(i, j) 收益率 [i, i+1, i+2, ..., j-1] 开始(!)默认为 0 . 当给定步骤时,它指定增量(或减量)。例如, range(4)range(0, 4, 1) 返回 [0, 1, 2, 3] . 省略了终点!这正是4个元素列表的有效索引。

这对于多次重复模板块很有用,例如填充列表。假设列表中有7个用户,但您希望呈现三个空项以使用css强制高度:

<ul>
{% for user in users %}
    <li>{{ user.username }}</li>
{% endfor %}
{% for number in range(10 - users|count) %}
    <li class="empty"><span>...</span></li>
{% endfor %}
</ul>
jinja-globals.lipsum(n=5, html=True, min=20, max=100)

为模板生成一些lorem ipsum。默认情况下,将生成5段HTML,每个段落的长度介于20到100个单词之间。如果html为false,则返回常规文本。这对于生成布局测试的简单内容很有用。

jinja-globals.dict(\**items)

听写文字的一种方便的替代方法。 {{'foo': 'bar'}} 是一样的 dict(foo='bar') .

class jinja-globals.cycler(\*items)

通过一次生成一个值来循环遍历这些值,然后在到达终点后重新启动。

类似 loop.cycle ,但可以在循环外部或多个循环之间使用。例如,在列表中呈现文件夹和文件的列表,交替为它们提供“奇数”和“偶数”类。

{% set row_class = cycler("odd", "even") %}
<ul class="browser">
{% for folder in folders %}
  <li class="folder {{ row_class.next() }}">{{ folder }}
{% endfor %}
{% for file in files %}
  <li class="file {{ row_class.next() }}">{{ file }}
{% endfor %}
</ul>
参数:

items -- 每个位置参数将按照每个循环给定的顺序生成。

Changelog

在 2.1 版本加入.

property current

返回当前项。相当于下次将返回的项 next() 被称为。

next()

返回当前项目,然后前进 current 到下一个项目。

reset()

将当前项重置为第一项。

class jinja-globals.joiner(sep=', ')

一个可以用来“连接”多个部分的小助手。一个连接符被传递一个字符串,每次调用它时都会返回该字符串,除了第一次(在这种情况下,它返回一个空字符串)。你可以用它来连接事物:

{% set pipe = joiner("|") %}
{% if categories %} {{ pipe() }}
    Categories: {{ categories|join(", ") }}
{% endif %}
{% if author %} {{ pipe() }}
    Author: {{ author() }}
{% endif %}
{% if can_edit %} {{ pipe() }}
    <a href="?action=edit">Edit</a>
{% endif %}
Changelog

在 2.1 版本加入.

class jinja-globals.namespace(...)

创建一个新容器,该容器允许使用 {{% set %}} 标签:

{% set ns = namespace() %}
{% set ns.foo = 'bar' %}

其主要目的是允许将值从循环体内部传递到外部范围。初始值可以作为dict、关键字参数或两者都提供(与python的行为相同) dict 构造函数::

{% set ns = namespace(found=false) %}
{% for item in items %}
    {% if item.check_something() %}
        {% set ns.found = true %}
    {% endif %}
    * {{ item.title }}
{% endfor %}
Found item having something: {{ ns.found }}
Changelog

在 2.10 版本加入.

扩展

以下部分介绍应用程序可能启用的内置Jinja扩展。应用程序还可以提供本文档未涵盖的进一步扩展;在这种情况下,应该有一个单独的文档解释 extensions .

i18n

如果 i18n扩展 则可以将模板中的文本标记为可翻译。若要将节标记为可翻译,请使用 trans 挡路:

{% trans %}Hello, {{ user }}!{% endtrans %}

在块内部,不允许使用语句,只允许文本和简单变量标记。

变量标记只能是名称,不能是属性访问、筛选器或其他表达式。若要使用表达式,请将其绑定到 trans 在块中使用的标记。

{% trans user=user.username %}Hello, {{ user }}!{% endtrans %}

若要绑定多个表达式,请使用逗号分隔每个表达式 (,

{% trans book_title=book.title, author=author.name %}
This is {{ book_title }} by {{ author }}
{% endtrans %}

要复数形式,请指定用 pluralize 标签。

{% trans count=list|length %}
There is {{ count }} {{ name }} object.
{% pluralize %}
There are {{ count }} {{ name }} objects.
{% endtrans %}

默认情况下,块中的第一个变量用于确定是使用单数形式还是复数形式。如果不正确,请指定用于复数形式的变量作为 pluralize .

{% trans ..., user_count=users|length %}...
{% pluralize user_count %}...{% endtrans %}

翻译文本块时,空格和换行符会导致翻译字符串难以阅读且容易出错。为了避免这种情况,可以将trans块标记为trimmed,这将用一个空格替换所有换行符及其周围的空白,并删除前导空格和尾随空格。

{% trans trimmed book_title=book.title %}
    This is {{ book_title }}.
    You should read it!
{% endtrans %}

这导致 This is %(book_title)s. You should read it! 在翻译文件中。

如果全局启用剪裁,则 notrimmed 修饰符可用于禁用块。

Changelog

在 2.10 版本加入: 这个 trimmednotrimmed 已添加修饰符。

如果翻译取决于消息所在的上下文,则 pgettextnpgettext 函数需要一个 context 字符串作为第一个参数,用于选择适当的翻译。属性指定上下文 {% trans %} 标记后,提供一个字符串作为第一个令牌 trans

{% trans "fruit" %}apple{% endtrans %}
{% trans "fruit" trimmed count -%}
    1 apple
{%- pluralize -%}
    {{ count }} apples
{%- endtrans %}

在 3.1 版本加入: 可以将上下文传递给 trans 要使用的标签 pgettextnpgettext

可以使用以下函数转换表达式中的字符串:

  • _(message) :别名 gettext

  • gettext(message) :翻译一条消息。

  • ngettext(singluar, plural, n) :根据计数变量翻译单数或复数消息。

  • pgettext(context, message) :喜欢 gettext() ,但根据上下文字符串选择翻译。

  • npgettext(context, singular, plural, n) :喜欢 npgettext() ,但根据上下文字符串选择翻译。

您可以像这样打印字符串:

{{ _("Hello, World!") }}

要使用占位符,请使用 format 过滤器。

{{ _("Hello, %(user)s!")|format(user=user.username) }}

始终使用关键字参数 format ,因为其他语言可能不使用相同顺序的单词。

如果 新样式Gettext 调用被激活,使用占位符更容易。格式化是 gettext 调用而不是使用 format 过滤器。

{{ gettext('Hello World!') }}
{{ gettext('Hello %(name)s!', name='World') }}
{{ ngettext('%(num)d apple', '%(num)d apples', apples|count) }}

这个 ngettext 函数的格式字符串自动将计数作为 num 除给定参数外的参数。

表达式语句

如果已加载表达式语句扩展名,则调用 do 与正则变量表达式的工作方式完全相同 ({{{{ ... }}}} )但它什么都不打印。这可用于修改列表:

{% do navigation.append('a string') %}

循环控制

如果应用程序启用 循环控制 ,可以使用 breakcontinue 在循环中。什么时候? break 到达时,循环终止;如果 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 %}

注意 loop.index 从1开始,然后 loop.index0 以0开头(请参见: 为了

调试语句

如果 调试扩展 已启用,a {{% debug %}} 标记将可用于转储当前上下文以及可用的筛选器和测试。这对于在不设置调试器的情况下查看模板中可使用的内容非常有用。

<pre>{% debug %}</pre>
{'context': {'cycler': <class 'jinja2.utils.Cycler'>,
             ...,
             'namespace': <class 'jinja2.utils.Namespace'>},
 'filters': ['abs', 'attr', 'batch', 'capitalize', 'center', 'count', 'd',
             ..., 'urlencode', 'urlize', 'wordcount', 'wordwrap', 'xmlattr'],
 'tests': ['!=', '<', '<=', '==', '>', '>=', 'callable', 'defined',
           ..., 'odd', 'sameas', 'sequence', 'string', 'undefined', 'upper']}

附有声明

Changelog

在 2.3 版本加入.

WITH语句使创建新的内部范围成为可能。在此范围内设置的变量在范围外不可见。

简而言之:

{% with %}
    {% set foo = 42 %}
    {{ foo }}           foo is 42 here
{% endwith %}
foo is not visible here any longer

因为在范围的开始设置变量是很常见的,所以可以在 with 语句。以下两个示例是等效的:

{% with foo = 42 %}
    {{ foo }}
{% endwith %}

{% with %}
    {% set foo = 42 %}
    {{ foo }}
{% endwith %}

关于范围界定的重要说明。在2.9之前的Jinja版本中,将一个变量引用到另一个变量的行为会产生一些意想不到的后果。尤其是,一个变量可以引用在同一with block的opening语句中定义的另一个变量。这导致了清理范围行为的问题,并已得到改进。特别是在较新的Jinja版本中,下面的代码总是引用变量 a 从外面 with 块::

{% with a={}, b=a.attribute %}...{% endwith %}

在早期的Jinja版本中, b 属性将引用第一个属性的结果。如果您依赖于此行为,则可以重写它以使用 set 标签:

{% with a={} %}
    {% set b = a.attribute %}
{% endwith %}

延伸

在旧版本的Jinja(2.9之前)中,需要通过扩展来启用此功能。它现在默认启用。

自动转义重写

Changelog

在 2.4 版本加入.

如果需要,可以从模板中激活和停用自动转义。

例子::

{% autoescape true %}
    Autoescaping is active within this block
{% endautoescape %}

{% autoescape false %}
    Autoescaping is inactive within this block
{% endautoescape %}

后一 endautoescape 这种行为会恢复到以前的状态。

延伸

在旧版本的Jinja(2.9之前)中,需要通过扩展来启用此功能。它现在默认启用。