鍍金池/ 教程/ Python/ 模板設(shè)計者文檔
提示和技巧
從其它的模板引擎切換
集成
沙箱
擴展
常見問題
介紹
模板設(shè)計者文檔
API

模板設(shè)計者文檔

這份文檔描述了模板引擎中的語法和語義結(jié)構(gòu),對于創(chuàng)建 Jinja 模板是一份相當(dāng)有用 的參考。因為模板引擎非常靈活,應(yīng)用中的配置會在分隔符和未定義值的行為方面與 這里的配置有細微差異。

概要

模板僅僅是文本文件。它可以生成任何基于文本的格式(HTML、XML、CSV、LaTex 等等)。 它并沒有特定的擴展名, .html.xml 都是可以的。

模板包含 變量表達式 ,這兩者在模板求值的時候會被替換為值。模板中 還有標(biāo)簽,控制模板的邏輯。模板語法的大量靈感來自于 Django 和 Python 。

下面是一個最小的模板,它闡明了一些基礎(chǔ)。我們會在文檔中后面的部分解釋細節(jié):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>My Webpage</title>
</head>
<body>
    <ul id="navigation">
    {% for item in navigation %}
        <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    {% endfor %}
    </ul>

    <h1>My Webpage</h1>
    {{ a_variable }}
</body>
</html>

這包含了默認的設(shè)定。應(yīng)用開發(fā)者也會把語法從 {% foo %} 改成 <% foo %> 或類似的東西。

這里有兩種分隔符: {% ... %}{{ ... }} 。前者用于執(zhí)行諸如 for 循環(huán) 或賦值的語句,后者把表達式的結(jié)果打印到模板上。

變量

應(yīng)用把變量傳遞到模板,你可能在模板中弄混。變量上面也可以有你能訪問的屬性或元 素。變量看起來是什么,完全取決于應(yīng)用提供了什么。

你可以使用點( . )來訪問變量的屬性,作為替代,也可以使用所謂的"下標(biāo)"語 法( [] )。下面的幾行效果是一樣的:

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

知曉花括號 不是 變量的一部分,而是打印語句的一部分是重要的。如果你訪問標(biāo)簽 里的不帶括號的變量。

如果變量或?qū)傩圆淮嬖?,會返回一個未定義值。你可以對這類值做什么取決于應(yīng)用的配 置,默認的行為是它如果被打印,其求值為一個空字符串,并且你可以迭代它,但其它 操作會失敗。

實現(xiàn)

為方便起見,Jinja2 中 foo.bar 在 Python 層中做下面的事情:

  • 檢查 foo 上是否有一個名為 bar 的屬性。
  • 如果沒有,檢查 foo 中是否有一個 'bar' 項 。
  • 如果沒有,返回一個未定義對象。

foo['bar'] 的方式相反,只在順序上有細小差異:

  • 檢查在 foo 中是否有一個 'bar' 項。
  • 如果沒有,檢查 foo 上是否有一個名為 bar 的屬性。
  • 如果沒有,返回一個未定義對象。

如果一個對象有同名的項和屬性,這很重要。此外,有一個 attr() 過濾 器,它只查找屬性。

過濾器

變量可以通過 過濾器 修改。過濾器與變量用管道符號( | )分割,并且也 可以用圓括號傳遞可選參數(shù)。多個過濾器可以鏈?zhǔn)秸{(diào)用,前一個過濾器的輸出會被作為 后一個過濾器的輸入。

例如 {{ name|striptags|title }} 會移除 name 中的所有 HTML 標(biāo)簽并且改寫 為標(biāo)題樣式的大小寫格式。過濾器接受帶圓括號的參數(shù),如同函數(shù)調(diào)用。這個例子會 把一個列表用逗號連接起來: {{ list|join(', ') }} 。

下面的 內(nèi)置過濾器清單 節(jié)介紹了所有的內(nèi)置過濾器。

測試

除了過濾器,所謂的"測試"也是可用的。測試可以用于對照普通表達式測試一個變量。 要測試一個變量或表達式,你要在變量后加上一個 is 以及測試的名稱。例如,要得出 一個值是否定義過,你可以用 name is defined ,這會根據(jù) name 是否定義返回 true 或 false 。

測試也可以接受參數(shù)。如果測試只接受一個參數(shù),你可以省去括號來分組它們。例如, 下面的兩個表達式做同樣的事情:

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

下面的 內(nèi)置測試清單 章節(jié)介紹了所有的內(nèi)置測試。

注釋

要把模板中一行的部分注釋掉,默認使用 {# ... #} 注釋語法。這在調(diào)試或 添加給你自己或其它模板設(shè)計者的信息時是有用的:

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

空白控制

默認配置中,模板引擎不會對空白做進一步修改,所以每個空白(空格、制表符、換行符 等等)都會原封不動返回。如果應(yīng)用配置了 Jinja 的 trim_blocks ,模板標(biāo)簽后的 第一個換行符會被自動移除(像 PHP 中一樣)。

此外,你也可以手動剝離模板中的空白。當(dāng)你在塊(比如一個 for 標(biāo)簽、一段注釋或變 量表達式)的開始或結(jié)束放置一個減號( - ),可以移除塊前或塊后的空白:

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

這會產(chǎn)出中間不帶空白的所有元素。如果 seq 是 19 的數(shù)字的列表, 輸出會是 123456789 。

如果開啟了 行語句 ,它們會自動去除行首的空白。

提示

標(biāo)簽和減號之間不能有空白。

有效的:

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

無效的:

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

轉(zhuǎn)義

有時想要或甚至必要讓 Jinja 忽略部分,不會把它作為變量或塊來處理。例如,如果 使用默認語法,你想在在使用把 {{ 作為原始字符串使用,并且不會開始一個變量 的語法結(jié)構(gòu),你需要使用一個技巧。

最簡單的方法是在變量分隔符中( {{ )使用變量表達式輸出:

{{ '{{' }}

對于較大的段落,標(biāo)記一個塊為 raw 是有意義的。例如展示 Jinja 語法的實例, 你可以在模板中用這個片段:

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

行語句

如果應(yīng)用啟用了行語句,就可以把一個行標(biāo)記為一個語句。例如如果行語句前綴配置為 # ,下面的兩個例子是等價的:

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

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

行語句前綴可以出現(xiàn)在一行的任意位置,只要它前面沒有文本。為了語句有更好的可讀 性,在塊的開始(比如 for 、 if 、 elif 等等)以冒號結(jié)尾:

# 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 開始,行注釋也可以使用了。例如如果配置 ## 為行注釋前綴, 行中所有 ## 之后的內(nèi)容(不包括換行符)會被忽略:

# for item in seq:
    <li>{{ item }}</li>     ## this comment is ignored
# endfor

模板繼承

Jinja 中最強大的部分就是模板繼承。模板繼承允許你構(gòu)建一個包含你站點共同元素的基 本模板"骨架",并定義子模板可以覆蓋的 。

聽起來復(fù)雜,實際上很簡單。從例子上手是最易于理解的。

基本模板

這個模板,我們會把它叫做 base.html ,定義了一個簡單的 HTML 骨架文檔,你可 能使用一個簡單的兩欄頁面。用內(nèi)容填充空的塊是子模板的工作:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        &copy; Copyright 2008 by <a >you</a>.
        {% endblock %}
    </div>
</body>

在本例中, {% block %} 標(biāo)簽定義了四個字幕版可以填充的塊。所有的 block 標(biāo)簽 告訴模板引擎子模板可以覆蓋模板中的這些部分。

子模板

一個子模板看起來是這樣:

{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
    {{ super() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
      Welcome on my awesome homepage.
    </p>
{% endblock %}

{% extend %} 標(biāo)簽是這里的關(guān)鍵。它告訴模板引擎這個模板"繼承"另一個模板。 當(dāng)模板系統(tǒng)對這個模板求值時,首先定位父模板。 extends 標(biāo)簽應(yīng)該是模板中的第一個 標(biāo)簽。它前面的所有東西都會按照普通情況打印出來,而且可能會導(dǎo)致一些困惑。更多 該行為的細節(jié)以及如何利用它,見 Null-Master 退回 。

模板的文件名依賴于模板加載器。例如 FileSystemLoader 允許你用文件名訪 問其它模板。你可以使用斜線訪問子目錄中的模板:

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

這種行為也可能依賴于應(yīng)用內(nèi)嵌的 Jinja 。注意子模板沒有定義 footer 塊,會 使用父模板中的值。

你不能在同一個模板中定義多個同名的 {% block %} 標(biāo)簽。因為塊標(biāo)簽以兩種 方向工作,所以存在這種限制。即一個塊標(biāo)簽不僅提供一個可以填充的部分,也在父級 定義填充的內(nèi)容。如果同一個模板中有兩個同名的 {% blok %} 標(biāo)簽,父模板 無法獲知要使用哪一個塊的內(nèi)容。

如果你想要多次打印一個塊,無論如何你可以使用特殊的 self 變量并調(diào)用與塊同名 的函數(shù):

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

Super 塊

可以調(diào)用 super 來渲染父級塊的內(nèi)容。這會返回父級塊的結(jié)果:

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

命名塊結(jié)束標(biāo)簽

Jinja2 允許你在塊的結(jié)束標(biāo)簽中加入的名稱來改善可讀性:

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

無論如何, endblock 后面的名稱一定與塊名匹配。

嵌套塊和作用域

嵌套塊可以勝任更復(fù)雜的布局。而默認的塊不允許訪問塊外作用域中的變量:

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

這個例子會輸出空的 項,因為 item 在塊中是不可用的。其原因是,如果 塊被子模板替換,變量在其塊中可能是未定義的或未被傳遞到上下文。

從 Jinja 2.2 開始,你可以顯式地指定在塊中可用的變量,只需在塊聲明中添加 scoped 修飾,就把塊設(shè)定到作用域中:

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

當(dāng)覆蓋一個塊時,不需要提供 scoped 修飾。

模板對象

當(dāng)一個模板對象被傳遞到模板上下文,你也可以從那個對象繼承。假設(shè)調(diào)用 代碼傳遞 layout_template 布局模板到環(huán)境,這段代碼會工作:

{% extends layout_template %}

之前 layout_template 變量一定是布局模板文件名的字符串才能工作。

HTML 轉(zhuǎn)義

當(dāng)從模板生成 HTML 時,始終有這樣的風(fēng)險:變量包含影響已生成 HTML 的字符。有兩種 解決方法:手動轉(zhuǎn)義每個字符或默認自動轉(zhuǎn)義所有的東西。

Jinja 兩者都支持,使用哪個取決于應(yīng)用的配置。默認的配置未開啟自動轉(zhuǎn)義有這樣幾個 原因:

  • 轉(zhuǎn)義所有非安全值的東西也意味著 Jijna 轉(zhuǎn)義已知不包含 HTML 的值,比如數(shù)字,對 性能有巨大影響。
  • 關(guān)于變量安全性的信息是易碎的。可能會發(fā)生強制標(biāo)記一個值為安全或非安全的情況, 而返回值會被作為 HTML 轉(zhuǎn)義兩次。

使用手動轉(zhuǎn)義

如果啟用了手動轉(zhuǎn)義,按需轉(zhuǎn)義變量就是 你的 責(zé)任。要轉(zhuǎn)義什么?如果你有 一個 可能 包含 > 、 < 、 &" 字符的變量,你必須轉(zhuǎn)義 它,除非變量中的 HTML 有可信的良好格式。轉(zhuǎn)義通過用管道傳遞到過濾器 |e 來實現(xiàn): {{ user.username|e }}

使用自動轉(zhuǎn)義

當(dāng)啟用了自動轉(zhuǎn)移,默認會轉(zhuǎn)移一切,除非值被顯式地標(biāo)記為安全的。可以在應(yīng)用中 標(biāo)記,也可以在模板中使用 |safe 過濾器標(biāo)記。這種方法的主要問題是 Python 本 身沒有被污染的值的概念,所以一個值是否安全的信息會丟失。如果這個信息丟失, 會繼續(xù)轉(zhuǎn)義,你最后會得到一個轉(zhuǎn)義了兩次的內(nèi)容。

但雙重轉(zhuǎn)義很容易避免,只需要依賴 Jinja2 提供的工具而不使用諸如字符串模運算符 這樣的 Python 內(nèi)置結(jié)構(gòu)。

返回模板數(shù)據(jù)(宏、 super 、 self.BLOCKNAME )的函數(shù),其返回值總是被標(biāo)記 為安全的。

模板中的字符串字面量在自動轉(zhuǎn)義中被也被視為是不安全的。這是因為安全的字符串是 一個對 Python 的擴展,而不是每個庫都能妥善地使用它。

控制結(jié)構(gòu)清單

控制結(jié)構(gòu)指的是所有的那些可以控制程序流的東西 —— 條件(比如 if/elif/ekse )、 for 循環(huán)、以及宏和塊之類的東西??刂平Y(jié)構(gòu)在默認語法中以 {% .. %} 塊的形式 出現(xiàn)。

For

遍歷序列中的每項。例如,要顯示一個由 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>

注意無論如何字典通常是無序的,所以你可能需要把它作為一個已排序的列表傳入 到模板或使用 dictsort 過濾器。

在一個 for 循環(huán)塊中你可以訪問這些特殊的變量:

變量 描述
loop.index 當(dāng)前循環(huán)迭代的次數(shù)(從 1 開始)
loop.index0 當(dāng)前循環(huán)迭代的次數(shù)(從 0 開始)
loop.revindex 到循環(huán)結(jié)束需要迭代的次數(shù)(從 1 開始)
loop.revindex0 到循環(huán)結(jié)束需要迭代的次數(shù)(從 0 開始)
loop.first 如果是第一次迭代,為 True 。
loop.last 如果是最后一次迭代,為 True 。
loop.length 序列中的項目數(shù)。
loop.cycle 在一串序列間期取值的輔助函數(shù)。見下面的解釋。

在 for 循環(huán)中,可以使用特殊的 loop.cycle 輔助函數(shù),伴隨循環(huán)在一個字符串/變 量列表中周期取值:

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

從 Jinja 2.1 開始,一個額外的 cycle 輔助函數(shù)允許循環(huán)限定外的周期取值。 更多信息請閱讀 全局函數(shù)清單 。

與 Python 中不同,模板中的循環(huán)內(nèi)不能 break 或 continue 。但你可以在迭代 中過濾序列來跳過項目。下面的例子中跳過了所有隱藏的用戶:

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

好處是特殊的 loop 可以正確地計數(shù),從而不計入未迭代過的用戶。

如果因序列是空或者過濾移除了序列中的所有項目而沒有執(zhí)行循環(huán),你可以使用 else 渲染一個用于替換的塊:

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

也可以遞歸地使用循環(huán)。當(dāng)你處理諸如站點地圖之類的遞歸數(shù)據(jù)時很有用。要遞歸地 使用循環(huán),你只需要在循環(huán)定義中加上 recursive 修飾,并在你想使用遞歸的地 方,對可迭代量調(diào)用 loop 變量。

下面的例子用遞歸循環(huán)實現(xiàn)了站點地圖:

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

If

Jinja 中的 if 語句可比 Python 中的 if 語句。在最簡單的形式中,你可以測試 一個變量是否未定義,為空或 false:

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

像在 Python 中一樣,用 elif 和 else 來構(gòu)建多個分支。你也可以用更復(fù)雜的 表達式:

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

If 也可以被用作 內(nèi)聯(lián)表達式 并作為 循環(huán)過濾 。

宏類似常規(guī)編程語言中的函數(shù)。它們用于把常用行為作為可重用的函數(shù),取代 手動重復(fù)的工作。

這里是一個宏渲染表單元素的小例子:

{% macro input(name, value='', type='text', size=20) -%}
    <input type="{{ type }}" name="{{ name }}" value="{{
        value|e }}" size="{{ size }}">
{%- endmacro %}

在命名空間中,宏之后可以像函數(shù)一樣調(diào)用:

<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>

如果宏在不同的模板中定義,你需要首先使用 import 。

在宏內(nèi)部,你可以訪問三個特殊的變量:

varargs
如果有多于宏接受的參數(shù)個數(shù)的位置參數(shù)被傳入,它們會作為列表的值保存在 varargs 變量上。
kwargs
同 varargs ,但只針對關(guān)鍵字參數(shù)。所有未使用的關(guān)鍵字參數(shù)會存儲在 這個特殊變量中。
caller
如果宏通過 call 標(biāo)簽調(diào)用,調(diào)用者會作為可調(diào)用的宏被存儲在這個 變量中。

宏也可以暴露某些內(nèi)部細節(jié)。下面的宏對象屬性是可用的:

name
宏的名稱。 {{ input.name }} 會打印 input
arguments
一個宏接受的參數(shù)名的元組。
defaults
默認值的元組。
catch_kwargs
如果宏接受額外的關(guān)鍵字參數(shù)(也就是訪問特殊的 kwargs 變量),為 true 。
catch_varargs
如果宏接受額外的位置參數(shù)(也就是訪問特殊的 varargs 變量),為 true 。
caller
如果宏訪問特殊的 caller 變量且由 call 標(biāo)簽調(diào)用,為 true 。

如果一個宏的名稱以下劃線開始,它不是導(dǎo)出的且不能被導(dǎo)入。

調(diào)用

在某些情況下,需要把一個宏傳遞到另一個宏。為此,可以使用特殊的 call 塊。 下面的例子展示了如何讓宏利用調(diào)用功能:

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

也可以向調(diào)用塊傳遞參數(shù)。這在為循環(huán)做替換時很有用。總而言之,調(diào)用塊的工作方 式幾乎與宏相同,只是調(diào)用塊沒有名稱。

這里是一個帶參數(shù)的調(diào)用塊的例子:

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

過濾器

過濾器段允許你在一塊模板數(shù)據(jù)上應(yīng)用常規(guī) Jinja2 過濾器。只需要把代碼用 filter 節(jié)包裹起來:

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

賦值

在代碼塊中,你也可以為變量賦值。在頂層的(塊、宏、循環(huán)之外)賦值是可導(dǎo)出的,即 可以從別的模板中導(dǎo)入。

賦值使用 set 標(biāo)簽,并且可以為多個變量賦值:

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

繼承

extends 標(biāo)簽用于從另一個模板繼承。你可以在一個文件中使用多次繼承,但是 只會執(zhí)行其中的一個。見上面的關(guān)于 模板繼承 的節(jié)。

塊用于繼承,同時作為占位符和用于替換的內(nèi)容。 模板繼承 節(jié)中詳細地介紹了塊。

包含

include 語句用于包含一個模板,并在當(dāng)前命名空間中返回那個文件的內(nèi)容渲 染結(jié)果:

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

被包含的模板默認可以訪問活動的上下文中的變量。更多關(guān)于導(dǎo)入和包含的上下文 行為見 導(dǎo)入上下文行為

從 Jinja 2.2 開始,你可以把一句 include 用 ignore missing 標(biāo)記,這樣 如果模板不存在,Jinja 會忽略這條語句。當(dāng)與 withwithout context 語句聯(lián)合使用時,它必須被放在上下文可見性語句 之前 。這里是一些有效的例 子:

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

Changed in version 2.4: 如果傳遞一個模板對象到模板上下文,你可以用 include 包含這個對 象。

導(dǎo)入

Jinja2 支持在宏中放置經(jīng)常使用的代碼。這些宏可以被導(dǎo)入,并不同的模板中使用。這 與 Python 中的 import 語句類似。要知道的是,導(dǎo)入量會被緩存,并且默認下導(dǎo)入的 模板不能訪問當(dāng)前模板中的非全局變量。更多關(guān)于導(dǎo)入和包含的上下文行為見 導(dǎo)入上下文行為

有兩種方式來導(dǎo)入模板。你可以把整個模板導(dǎo)入到一個變量或從其中導(dǎo)入請求特定的宏 /導(dǎo)出量。

比如我們有一個渲染表單(名為 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 %}

最簡單靈活的方式是把整個模塊導(dǎo)入為一個變量。這樣你可以訪問屬性:

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

此外你也可以從模板中導(dǎo)入名稱到當(dāng)前的命名空間:

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

名稱以一個或更多下劃線開始的宏和變量是私有的,不能被導(dǎo)入。

Changed in version 2.4: 如果傳遞一個模板對象到模板上下文,從那個對象中導(dǎo)入。

導(dǎo)入上下文行為

默認下,每個包含的模板會被傳遞到當(dāng)前上下文,而導(dǎo)入的模板不會。這樣做的原因 是導(dǎo)入量不會像包含量被緩存,因為導(dǎo)入量經(jīng)常只作容納宏的模塊。

無論如何,這當(dāng)然也可以顯式地更改。通過在 import/include 聲明中直接添加 with context 或 without context ,當(dāng)前的上下文可以傳遞到模板,而且不會 自動禁用緩存。

這里有兩個例子:

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

提示

在 Jinja 2.0 中,被傳遞到被包含模板的上下文不包含模板中定義的變量。 事實上,這不能工作:

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

在 Jinja 2.0 中,被包含的模板 render_box.html 不能 訪問 box 。從 Jinja 2.1 開始, render_box.html 可以 這么做。

表達式

Jinja 中到處都允許使用基本表達式。這像常規(guī)的 Python 一樣工作,即使你不用 Python 工作,你也會感受到其帶來的便利。

字面量

表達式最簡單的形式就是字面量。字面量表示諸如字符串和數(shù)值的 Python 對象。下面 的字面量是可用的:

"Hello World":
雙引號或單引號中間的一切都是字符串。無論何時你需要在模板中使用一個字 符串(比如函數(shù)調(diào)用、過濾器或只是包含或繼承一個模板的參數(shù)),它們都是 有用的。
42 / 42.23:
直接寫下數(shù)值就可以創(chuàng)建整數(shù)和浮點數(shù)。如果有小數(shù)點,則為浮點數(shù),否則為 整數(shù)。記住在 Python 里, 4242.0 是不一樣的。
['list', 'of', 'objects']:

一對中括號括起來的東西是一個列表。列表用于存儲和迭代序列化的數(shù)據(jù)。例如 你可以容易地在 for 循環(huán)中用列表和元組創(chuàng)建一個鏈接的列表:

<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'):
元組與列表類似,只是你不能修改元組。如果元組中只有一個項,你需要以逗號 結(jié)尾它。元組通常用于表示兩個或更多元素的項。更多細節(jié)見上面的例子。
{'dict': 'of', 'key': 'and', 'value': 'pairs'}:
Python 中的字典是一種關(guān)聯(lián)鍵和值的結(jié)構(gòu)。鍵必須是唯一的,并且鍵必須只有一個 值。字典在模板中很少使用,罕用于諸如 xmlattr() 過濾器之類。
true / false:
true 永遠是 true ,而 false 始終是 false 。

提示

特殊常量 true 、 false 和 none 實際上是小寫的。因為這在過去會導(dǎo)致 混淆,過去 True 擴展為一個被認為是 false 的未定義的變量。所有的這三個 常量也可以被寫成首字母大寫( True 、 False 和 None )。盡管如此, 為了一致性(所有的 Jinja 標(biāo)識符是小寫的),你應(yīng)該使用小寫的版本。

算術(shù)

Jinja 允許你用計算值。這在模板中很少用到,但是為了完整性允許其存在。支持下面的 運算符:

+
把兩個對象加到一起。通常對象是素質(zhì),但是如果兩者是字符串或列表,你可以用這 種方式來銜接它們。無論如何這不是首選的連接字符串的方式!連接字符串見 ~ 運算符。 {{ 1 + 1 }} 等于 2 。
-
用第一個數(shù)減去第二個數(shù)。 {{ 3 - 2 }} 等于 1
/
對兩個數(shù)做除法。返回值會是一個浮點數(shù)。 {{ 1 / 2 }} 等于 {{ 0.5 }}
//
對兩個數(shù)做除法,返回整數(shù)商。 {{ 20 // 7 }} 等于 2
%
計算整數(shù)除法的余數(shù)。 {{ 11 % 7 }} 等于 4
*
用右邊的數(shù)乘左邊的操作數(shù)。 {{ 2 * 2 }} 會返回 4 。也可以用于重 復(fù)一個字符串多次。 {{ '=' * 80 }} 會打印 80 個等號的橫條。
**
取左操作數(shù)的右操作數(shù)次冪。 {{ 2**3 }} 會返回 8 。

比較

==
比較兩個對象是否相等。
!=
比較兩個對象是否不等。

: 如果左邊大于右邊,返回 true 。

=
如果左邊大于等于右邊,返回 true 。
<
如果左邊小于右邊,返回 true 。
<=
如果左邊小于等于右邊,返回 true 。

邏輯

對于 if 語句,在 for 過濾或 if 表達式中,它可以用于聯(lián)合多個表達式:

and
如果左操作數(shù)和右操作數(shù)同為真,返回 true 。
or
如果左操作數(shù)和右操作數(shù)有一個為真,返回 true 。
not
對一個表達式取反(見下)。
(expr)
表達式組。

提示

isin 運算符同樣支持使用中綴記法: foo is not barfoo not in bar 而不是 not foo is barnot foo in bar 。所有的 其它表達式需要前綴記法 not (foo and bar)

其它運算符

下面的運算符非常有用,但不適用于其它的兩個分類:

in
運行序列/映射包含檢查。如果左操作數(shù)包含于右操作數(shù),返回 true 。比如 {{ 1 in [1,2,3] }} 會返回 true 。
is
運行一個 測試
|
應(yīng)用一個 過濾器
~
把所有的操作數(shù)轉(zhuǎn)換為字符串,并且連接它們。 {{ "Hello " ~ name ~ "!" }} 會返回(假設(shè) name 值為 ''John'Hello John!
()
調(diào)用一個可調(diào)用量:{{ post.render() }} 。在圓括號中,你可以像在 python 中一樣使用位置參數(shù)和關(guān)鍵字參數(shù): {{ post.render(user, full=true) }} 。
. / []
獲取一個對象的屬性。(見 變量

If 表達式

同樣,也可以使用內(nèi)聯(lián)的 if 表達式。這在某些情況很有用。例如你可以用來在一個 變量定義的情況下才繼承一個模板,否則繼承默認的布局模板:

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

一般的語法是 if else 。

else 部分是可選的。如果沒有顯式地提供 else 塊,會求值一個未定義對象:

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

內(nèi)置過濾器清單

abs(number)

Return the absolute value of the argument.

attr(obj, name)

Get an attribute of an object. foo|attr("bar") works like foo["bar"] just that always an attribute is returned and items are not looked up.

See Notes on subscriptions for more details.

batch(value, linecount, _fillwith=None)

A filter that batches items. It works pretty much like slice just the other way round. It returns a list of lists with the given number of items. If you provide a second parameter this is used to fill up missing items. See this example:

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

Capitalize a value. The first character will be uppercase, all others lowercase.

center(value, width=80)

Centers the value in a field of a given width.

default(value, _defaultvalue=u'', boolean=False)

If the value is undefined it will return the passed default value, otherwise the value of the variable:

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

This will output the value of my_variable if the variable was defined, otherwise 'my_variable is not defined'. If you want to use default with variables that evaluate to false you have to set the second parameter to true:

{{ ''|default('the string was empty', true) }}
dictsort(value, _casesensitive=False, by='key')

Sort a dict and yield (key, value) pairs. Because python dicts are unsorted you may want to use this function to order them by either key or value:

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

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

{% for item in mydict|dictsort(false, 'value') %}
    sort the dict by key, case insensitive, sorted
    normally and ordered by value.
escape(s)

Convert the characters &, <, >, ', and " in string s to HTML-safe sequences. Use this if you need to display text that might contain such characters in HTML. Marks return value as markup string.

filesizeformat(value, binary=False)

Format the value like a 'human-readable' file size (i.e. 13 kB, 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, Giga, etc.), if the second parameter is set to True the binary prefixes are used (Mebi, Gibi).

first(seq)

Return the first item of a sequence.

float(value, default=0.0)

Convert the value into a floating point number. If the conversion doesn't work it will return 0.0. You can override this default using the first parameter.

forceescape(value)

Enforce HTML escaping. This will probably double escape variables.

format(value, *args, **kwargs)

Apply python string formatting on an object:

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

Group a sequence of objects by a common attribute.

If you for example have a list of dicts or objects that represent persons with gender, first_name and last_name attributes and you want to group all users by genders you can do something like the following snippet:

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

Additionally it's possible to use tuple unpacking for the grouper and list:

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

As you can see the item we're grouping by is stored in the grouper attribute and the list contains all the objects that have this grouper in common.

Changed in version 2.6: It's now possible to use dotted notation to group by the child attribute of another attribute.

indent(s, width=4, indentfirst=False)

Return a copy of the passed string, each line indented by 4 spaces. The first line is not indented. If you want to change the number of spaces or indent the first line too you can pass additional parameters to the filter:

{{ mytext|indent(2, true) }}
    indent by two spaces and indent the first line too.
int(value, default=0)

Convert the value into an integer. If the conversion doesn't work it will return 0. You can override this default using the first parameter.

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

Return a string which is the concatenation of the strings in the sequence. The separator between elements is an empty string per default, you can define it with the optional parameter:

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

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

It is also possible to join certain attributes of an object:

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

New in version 2.6: The attribute parameter was added.

last(seq)

Return the last item of a sequence.

length(object)

Return the number of items of a sequence or mapping.

list(value)

Convert the value into a list. If it was a string the returned list will be a list of characters.

lower(s)

Convert a value to lowercase.

map()

Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with lists of objects but you are really only interested in a certain value of it.

The basic usage is mapping on an attribute. Imagine you have a list of users but you are only interested in a list of usernames:

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

Alternatively you can let it invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence:

Users on this page: {{ titles|map('lower')|join(', ') }}
pprint(value, verbose=False)

Pretty print a variable. Useful for debugging.

With Jinja 1.2 onwards you can pass it a parameter. If this parameter is truthy the output will be more verbose (this requires pretty)

random(seq)

Return a random item from the sequence.

reject()

Filters a sequence of objects by appying a test to either the object or the attribute and rejecting the ones with the test succeeding.

Example usage:

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

Filters a sequence of objects by appying a test to either the object or the attribute and rejecting the ones with the test succeeding.

{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}
replace(s, old, new, count=None)

Return a copy of the value with all occurrences of a substring replaced with a new one. The first argument is the substring that should be replaced, the second is the replacement string. If the optional third argument count is given, only the first count occurrences are replaced:

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

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

Reverse the object or return an iterator the iterates over it the other way round.

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

Round the number to a given precision. The first parameter specifies the precision (default is 0), the second the rounding method:

  • 'common' rounds either up or down
  • 'ceil' always rounds up
  • 'floor' always rounds down

If you don't specify a method 'common' is used.

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

Note that even if rounded to 0 precision, a float is returned. If you need a real integer, pipe it through int:

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