模板设计器文档

本文档描述了模板引擎的语法和语义,对于创建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分隔符配置如下:

变量

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

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

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

以下几行的作用相同:

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

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

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

实施

为了方便起见, foo.bar 在jinja2中,在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>

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

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

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

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

默认情况下,jinja2还删除尾随新行。要保留单个尾随换行符,请将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 标记的作用是告诉模板引擎子模板可能会覆盖模板中的那些占位符。

子模板

子模板可能如下所示:

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

命名块结束标记

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

{% 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 不必提供修饰符。

模板对象

在 2.4 版更改.

如果模板对象是在模板上下文中传递的,则也可以从该对象进行扩展。假设调用代码将布局模板作为 layout_template 对于环境,此代码的作用是:

{% extends layout_template %}

以前, layout_template 变量必须是具有布局模板文件名的字符串才能工作。

HTML逃逸

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

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

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

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

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

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

使用手动逃逸

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

{{ user.username|e }}

使用自动转义

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

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

  2. 模板,与 |safe 滤波器

这种方法的主要问题是,python本身没有污染值的概念;因此,值是安全的还是不安全的都会丢失。

如果一个值没有被标记为安全,则会发生自动转义;这意味着您可能会以双重转义内容结束。然而,双重逃逸是很容易避免的:仅仅依靠Jinja2提供的工具和 不要使用内置的python结构,如str.format或string modulo运算符(%) .

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

具有自动转义的模板中的字符串文本被认为是不安全的,因为本机python字符串 (strunicodebasestring 不是) MarkupSafe.Markup strings with an ``_ _ html_uu``属性。

控制结构清单

控制结构指的是控制程序流的所有东西——循环的条件(即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.iteritems() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

但是,请注意 未订购python dict ;因此,您可能希望通过 list 属于 tuple S-或A collections.OrderedDict --到模板,或使用 dictsort 过滤器。

在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(...) }}}}

请注意,循环中的赋值将在迭代结束时清除,并且不能超出循环范围。旧版本的jinja2有一个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

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

defaults

默认值的元组。

catch_kwargs

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

catch_varargs

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

caller

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

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

呼叫

在某些情况下,将宏传递给另一个宏可能很有用。为此,您可以使用 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>
        <dl>Realname</dl>
        <dd>{{ user.realname|e }}</dd>
        <dl>Description</dl>
        <dd>{{ user.description }}</dd>
    </dl>
{% endcall %}

过滤器

过滤部分允许您在模板数据块上应用常规的jinja2过滤器。只需将代码包装在 filter 章节:

{% filter upper %}
    This text becomes uppercase
{% 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 标记只允许用于命名空间对象;尝试在任何其他对象上分配属性将引发异常。

2.10 新版功能: 添加了对命名空间对象的支持

阻止分配

2.8 新版功能.

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

例子::

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

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

在 2.10 版更改.

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

例子::

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

延伸

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

参见关于 模板继承 上面。

阻碍

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

包括

这个 include 标记用于包含模板并将该文件的呈现内容返回到当前命名空间::

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

默认情况下,包含的模板可以访问活动上下文的变量。有关导入和包含的上下文行为的详细信息,请参阅 导入上下文行为 .

从Jinja 2.2起,您可以标记包含 ignore missing ;在这种情况下,如果要包含的模板不存在,Jinja将忽略该语句。当与 withwithout context ,必须放置 之前 上下文可见性语句。以下是一些有效的示例:

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

2.2 新版功能.

还可以提供在包含之前已检查是否存在的模板列表。将包括存在的第一个模板。如果 ignore missing 如果不存在任何模板,则返回到“不渲染”,否则将引发异常。

例子::

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

在 2.4 版更改: 如果模板对象已传递到模板上下文,则可以使用 include .

输入

Jinja2支持将常用代码放入宏中。这些宏可以进入不同的模板并从那里导入。这与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>

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

在 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对象(如字符串和数字)的表示形式。存在以下文字:

“你好世界”:

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

42/42.23:

整数和浮点数是通过只写下数字来创建的。如果存在一个点,则数字是一个浮点数,否则是一个整数。记住,在python中, 4242.0 是不同的 (intfloat ,分别)。

['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() 过滤器。

真/假:

真是真,假是假。

注意

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

数学

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

+

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

-

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

/

把两个数字分开。返回值将是一个浮点数。 {{{{ 1 / 2 }}}}{{{{ 0.5 }}}} . (就像 from __future__ import division

/ /

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

%

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

*

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

* *

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

比较

=

比较两个对象是否相等。

!=

比较两个对象的不等式。

>

true 如果左侧大于右侧。

>

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

<

true 如果左侧低于右侧。

<=

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

逻辑

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

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

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

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

(EXPR)

将表达式分组。

注意

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

其他经营者

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

在里面

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

执行一个 test .

应用A filter .

~

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

{{{{ "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 'master.html' %}

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

这个 else 部分是可选的。如果未提供,则else块将隐式计算为未定义的对象:

{{ ('[%s]' % page.title) if page.title }}

内置过滤器列表

内置筛选器索引

abs()

attr()

batch()

capitalize()

center()

default()

dictsort()

escape()

filesizeformat()

first()

float()

forceescape()

format()

groupby()

indent()

int()

join()

last()

length()

list()

lower()

map()

max()

min()

pprint()

random()

reject()

rejectattr()

replace()

reverse()

round()

safe()

select()

selectattr()

slice()

sort()

string()

striptags()

sum()

title()

tojson()

trim()

truncate()

unique()

upper()

urlencode()

urlize()

wordcount()

wordwrap()

xmlattr()

abs()

返回参数的绝对值。

attr(obj, name)

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

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

batch(value, linecount, fill_with=None)

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

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

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

center(value, width=80)

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

default(value, default_value='', boolean=False)

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

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

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

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

d

dictsort(value, case_sensitive=False, by='key', reverse=False)

对dict进行排序并生成(key,value)对。因为python dicts是未排序的,所以您可能希望使用此函数按键或值对其进行排序:

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

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

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

{% for item in mydict|dictsort(false, 'value') %}
    sort the dict by value, case insensitive
escape(s)

将字符串S中的字符&、<、>、'和“转换为HTML安全序列”。如果需要在HTML中显示可能包含此类字符的文本,请使用此选项。将返回值标记为标记字符串。

别名

e

filesizeformat(value, binary=False)

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

first(seq)

返回序列的第一项。

float(value, default=0.0)

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

forceescape(value)

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

format(value, *args, **kwargs)

对对象应用python字符串格式:

{{ "%s - %s"|format("Hello?", "Foo!") }}
    -> Hello? - Foo!
groupby(value, attribute)

按公共属性对对象序列进行分组。

例如,如果您有一个代表 genderfirst_namelast_name 属性,并且要按性别对所有用户分组,您可以执行如下操作:

<ul>
{% for group in persons|groupby('gender') %}
    <li>{{ group.grouper }}<ul>
    {% for person in group.list %}
        <li>{{ person.first_name }} {{ person.last_name }}</li>
    {% endfor %}</ul></li>
{% endfor %}
</ul>

此外,还可以为grouper和list使用tuple解包:

<ul>
{% for grouper, list in persons|groupby('gender') %}
    ...
{% endfor %}
</ul>

如您所见,我们分组的项存储在 grouper 属性和 list 包含所有具有此Grouper的共同对象。

在 2.6 版更改: 现在可以使用点符号按另一个属性的子属性分组。

indent(s, width=4, first=False, blank=False, indentfirst=None)

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

参数
  • width -- 要缩进的空格数。

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

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

在 2.10 版更改: 默认情况下,空行不缩进。

重命名 indentfirst 参数 first .

int(value, default=0, base=10)

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

join(value, d='', attribute=None)

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

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

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

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

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

2.6 新版功能: 这个 attribute 已添加参数。

last(seq)

返回序列的最后一项。

length()

返回容器中的项目数。

别名

count

list(value)

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

lower(s)

将值转换为小写。

map()

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

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

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

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

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

2.7 新版功能.

max(value, case_sensitive=False, attribute=None)

返回序列中最大的项。

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

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

min(value, case_sensitive=False, attribute=None)

返回序列中最小的项。

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

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

pprint(value, verbose=False)

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

在Jinja 1.2之后,您可以传递一个参数。如果此参数正确,则输出将更详细(这需要 pretty

random(seq)

从序列中返回随机项。

reject()

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

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

示例用法:

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

2.7 新版功能.

rejectattr()

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

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

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

2.7 新版功能.

replace(s, old, new, count=None)

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

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

{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
    -> d'oh, d'oh, aaargh
reverse(value)

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

round(value, precision=0, method='common')

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

  • 'common' 向上或向下舍入

  • 'ceil' 总是向上搜索

  • 'floor' 总是向下舍入

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

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

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

{{ 42.55|round|int }}
    -> 43
safe(value)

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

select()

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

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

示例用法:

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

2.7 新版功能.

selectattr()

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

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

示例用法:

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

2.7 新版功能.

slice(value, slices, fill_with=None)

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

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

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

sort(value, reverse=False, case_sensitive=False, attribute=None)

对iterable排序。默认情况下,它按升序排序,如果您将它作为第一个参数传递true,它将反转排序。

如果iterable由字符串组成,则第三个参数可用于控制比较的区分大小写,默认情况下禁用比较。

{% for item in iterable|sort %}
    ...
{% endfor %}

也可以通过指定 attribute 参数:

{% for item in iterable|sort(attribute='date') %}
    ...
{% endfor %}

在 2.6 版更改: 这个 attribute 已添加参数。

string(object)

如果字符串不是Unicode,则将其设置为Unicode。这样标记字符串就不会转换回Unicode。

striptags(value)

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

sum(iterable, attribute=None, start=0)

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

也可以只总结某些属性:

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

在 2.6 版更改: 这个 attribute 添加了参数以允许对属性进行汇总。也 start 参数已移到右侧。

title(s)

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

tojson(value, indent=None)

将结构转储到JSON,以便在 <script> 标签。它接受相同的参数并返回一个JSON字符串。请注意,在模板中可以通过 |tojson 将结果标记为安全的筛选器。由于此函数如何转义某些字符,因此即使在 <script> 标签。

以下字符在字符串中转义:

  • <

  • >

  • &

  • '

这使得在HTML中的任何地方嵌入这样的字符串都是安全的,值得注意的是,双引号属性除外。在这种情况下,单引号您的属性或HTML转义它。

indent参数可用于启用漂亮打印。将其设置为结构应缩进的空格数。

请注意,此筛选器仅在HTML上下文中使用。

2.9 新版功能.

trim(value)

去掉前导空格和尾随空格。

truncate(s, length=255, killwords=False, end='...', leeway=None)

返回字符串的截断副本。长度由第一个参数指定,默认为 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..."

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

unique(value, case_sensitive=False, attribute=None)

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

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

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

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

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

upper(s)

将值转换为大写。

urlencode(value)

用于URL的转义字符串(使用UTF-8编码)。它接受字典、正则字符串以及成对的iterables。

2.7 新版功能.

urlize(value, trim_url_limit=None, nofollow=False, target=None, rel=None)

将纯文本格式的URL转换为可单击的链接。

如果您向过滤器传递一个额外的整数,它将把URL缩短到该数字。还有第三个参数使URL“nofollow”:

{{ mytext|urlize(40, true) }}
    links are shortened to 40 chars and defined with rel="nofollow"

如果 目标 是指定的, target 属性将添加到 <a> 标签:

{{ mytext|urlize(40, target='_blank') }}

在 2.8+ 版更改: 这个 目标 已添加参数。

wordcount(s)

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

wordwrap(s, width=79, break_long_words=True, wrapstring=None)

返回传递给筛选器的字符串的副本,该字符串在 79 字符。可以使用第一个参数重写此默认值。如果将第二个参数设置为 false 如果单词的长度超过 width . 默认情况下,换行将是环境的默认换行,但可以使用wrapString关键字参数更改。

2.7 新版功能: 增加了对 wrapstring 参数。

xmlattr(d, autospace=True)

基于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,否则它会自动在项目前面预留一个空格。

内置测试列表

内置测试索引

callable()

defined()

divisibleby()

eq()

escaped()

even()

ge()

gt()

in()

iterable()

le()

lower()

lt()

mapping()

ne()

none()

number()

odd()

sameas()

sequence()

string()

undefined()

callable()

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

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

defined(value)

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

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

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

divisibleby(value, num)

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

eq(a, b)
别名

==, equalto

escaped(value)

检查值是否已转义。

even(value)

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

ge(a, b)
别名

>=

gt(a, b)
别名

>, greaterthan

in(value, seq)

检查值是否在seq中。

2.10 新版功能.

iterable(value)

检查是否可以迭代对象。

le(a, b)
别名

<=

lower(value)

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

lt(a, b)
别名

<, lessthan

mapping(value)

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

2.6 新版功能.

ne(a, b)
别名

!=

none(value)

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

number(value)

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

odd(value)

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

sameas(value, other)

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

{% if foo.attribute is sameas false %}
    the foo attribute really is the `False` singleton
{% endif %}
sequence(value)

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

string(value)

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

undefined(value)

喜欢 defined() 但反过来说。

upper(value)

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

全局函数列表

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

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>
lipsum(n=5, html=True, min=20, max=100)

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

dict(**items)

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

class cycler(*items)

cycler允许您在类似于 loop.cycle 作品。不像 loop.cycle ,可以在循环之外或在多个循环上使用此循环器。

如果要显示文件夹和文件的列表,并且这些文件夹位于顶部,但它们都位于同一列表中,并且具有交替的行颜色,则这非常有用。

下面的示例显示了 cycler 可用于:

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

Cycler具有以下属性和方法:

reset()

将周期重置为第一项。

next()

向前移动一项并返回当时的当前项。

current

返回当前项。

2.1 新版功能.

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

2.1 新版功能.

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

2.10 新版功能.

扩展

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

i18n

如果启用了i18n扩展,则可以将模板中的部件标记为可翻译。要将节标记为可翻译,可以使用 trans ::

<p>{% trans %}Hello {{ user }}!{% endtrans %}</p>

要转换模板表达式(例如,使用模板过滤器,或者只访问对象的属性),需要将表达式绑定到名称,以便在转换块中使用:

<p>{% trans user=user.username %}Hello {{ user }}!{% endtrans %}</p>

如果需要在 trans 标记,用逗号分隔 (, ):

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

在trans标记中不允许使用任何语句,只允许使用变量标记。

若要复数,请使用 pluralize 标签,显示在 transendtrans ::

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

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

2.10 新版功能: 这个 trimmednotrimmed 已添加修饰符。

也可以在表达式中转换字符串。为此,有三个功能:

  • gettext :转换单个字符串

  • ngettext :转换可复数字符串

  • _: alias for gettext

例如,您可以轻松地打印这样的翻译字符串:

{{ _('Hello World!') }}

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

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

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

在 2.5 版更改.

如果激活newStyle getText调用 (空白剪裁 )使用占位符更容易:

{{ 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开头(请参见: 为了

附有声明

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版本中,将一个变量引用到另一个变量的行为会产生一些意想不到的结果。尤其是,一个变量可以引用同一个变量中定义的另一个变量WITHBLOCK的OPENING语句。这导致了清理范围行为的问题,并且已经得到了改进。尤其是在较新的jinja2版本中,以下代码始终引用变量 a 从外面 with 块::

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

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

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

延伸

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

自动转义重写

2.4 新版功能.

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

例子::

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

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

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

延伸

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