控制結(jié)構(gòu)指的是所有的那些可以控制程序流的東西 —— 條件(比如 if/elif/ekse )、 for 循環(huán)、以及宏和塊之類的東西??刂平Y(jié)構(gòu)在默認(rèn)語法中以?{%?..?%}?塊的形式 出現(xiàn)。
遍歷序列中的每項(xiàng)。例如,要顯示一個(gè)由?users`?變量提供的用戶列表:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
因?yàn)槟0逯械淖兞勘A羲鼈兊膶?duì)象屬性,可以迭代像?dict?的容器:
<dl>
{% for key, value in my_dict.iteritems() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
</dl>
注意無論如何字典通常是無序的,所以你可能需要把它作為一個(gè)已排序的列表傳入 到模板或使用?dictsort?過濾器。
在一個(gè) 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 | 序列中的項(xiàng)目數(shù)。 |
loop.cycle | 在一串序列間期取值的輔助函數(shù)。見下面的解釋。 |
在 for 循環(huán)中,可以使用特殊的?loop.cycle?輔助函數(shù),伴隨循環(huán)在一個(gè)字符串/變 量列表中周期取值:
{% for row in rows %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
從 Jinja 2.1 開始,一個(gè)額外的?cycle?輔助函數(shù)允許循環(huán)限定外的周期取值。 更多信息請(qǐng)閱讀?全局函數(shù)清單?。
與 Python 中不同,模板中的循環(huán)內(nèi)不能?break?或?continue?。但你可以在迭代 中過濾序列來跳過項(xiàng)目。下面的例子中跳過了所有隱藏的用戶:
{% for user in users if not user.hidden %}
<li>{{ user.username|e }}</li>
{% endfor %}
好處是特殊的?loop?可以正確地計(jì)數(shù),從而不計(jì)入未迭代過的用戶。
如果因序列是空或者過濾移除了序列中的所有項(xiàng)目而沒有執(zhí)行循環(huán),你可以使用?else?渲染一個(gè)用于替換的塊:
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% else %}
<li><em>no users found</em></li>
{% endfor %}
</ul>
也可以遞歸地使用循環(huán)。當(dāng)你處理諸如站點(diǎn)地圖之類的遞歸數(shù)據(jù)時(shí)很有用。要遞歸地 使用循環(huán),你只需要在循環(huán)定義中加上?recursive?修飾,并在你想使用遞歸的地 方,對(duì)可迭代量調(diào)用?loop?變量。
下面的例子用遞歸循環(huán)實(shí)現(xiàn)了站點(diǎ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>
Jinja 中的?if?語句可比 Python 中的 if 語句。在最簡(jiǎn)單的形式中,你可以測(cè)試 一個(gè)變量是否未定義,為空或 false:
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
像在 Python 中一樣,用?elif?和?else?來構(gòu)建多個(gè)分支。你也可以用更復(fù)雜的?表達(dá)式:
{% 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)表達(dá)式?并作為?循環(huán)過濾?。
宏類似常規(guī)編程語言中的函數(shù)。它們用于把常用行為作為可重用的函數(shù),取代 手動(dòng)重復(fù)的工作。
這里是一個(gè)宏渲染表單元素的小例子:
{% 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)部,你可以訪問三個(gè)特殊的變量:
varargs
如果有多于宏接受的參數(shù)個(gè)數(shù)的位置參數(shù)被傳入,它們會(huì)作為列表的值保存在?varargs變量上。
kwargs
同?varargs?,但只針對(duì)關(guān)鍵字參數(shù)。所有未使用的關(guān)鍵字參數(shù)會(huì)存儲(chǔ)在 這個(gè)特殊變量中。
caller
如果宏通過?call?標(biāo)簽調(diào)用,調(diào)用者會(huì)作為可調(diào)用的宏被存儲(chǔ)在這個(gè) 變量中。
宏也可以暴露某些內(nèi)部細(xì)節(jié)。下面的宏對(duì)象屬性是可用的:
name
宏的名稱。?{{?input.name?}}?會(huì)打印?input?。
arguments
一個(gè)宏接受的參數(shù)名的元組。
defaults
默認(rèn)值的元組。
catch_kwargs
如果宏接受額外的關(guān)鍵字參數(shù)(也就是訪問特殊的?kwargs?變量),為?true?。
catch_varargs
如果宏接受額外的位置參數(shù)(也就是訪問特殊的?varargs?變量),為?true?。
caller
如果宏訪問特殊的?caller?變量且由?call?標(biāo)簽調(diào)用,為?true?。
如果一個(gè)宏的名稱以下劃線開始,它不是導(dǎo)出的且不能被導(dǎo)入。
在某些情況下,需要把一個(gè)宏傳遞到另一個(gè)宏。為此,可以使用特殊的?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)做替換時(shí)很有用。總而言之,調(diào)用塊的工作方 式幾乎與宏相同,只是調(diào)用塊沒有名稱。
這里是一個(gè)帶參數(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)簽,并且可以為多個(gè)變量賦值:
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
extends?標(biāo)簽用于從另一個(gè)模板繼承。你可以在一個(gè)文件中使用多次繼承,但是 只會(huì)執(zhí)行其中的一個(gè)。見上面的關(guān)于?模板繼承?的節(jié)。
塊用于繼承,同時(shí)作為占位符和用于替換的內(nèi)容。?模板繼承?節(jié)中詳細(xì)地介紹了塊。
include?語句用于包含一個(gè)模板,并在當(dāng)前命名空間中返回那個(gè)文件的內(nèi)容渲 染結(jié)果:
{% include 'header.html' %}
Body
{% include 'footer.html' %}
被包含的模板默認(rèn)可以訪問活動(dòng)的上下文中的變量。更多關(guān)于導(dǎo)入和包含的上下文 行為見導(dǎo)入上下文行為?。
從 Jinja 2.2 開始,你可以把一句 include 用?ignore?missing?標(biāo)記,這樣 如果模板不存在,Jinja 會(huì)忽略這條語句。當(dāng)與?with?或?without?context?語句聯(lián)合使用時(shí),它必須被放在上下文可見性語句?之前?。這里是一些有效的例 子:
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}
New in version 2.2.
你也可以提供一個(gè)模板列表,它會(huì)在包含前被檢查是否存在。第一個(gè)存在的模板會(huì) 被包含進(jìn)來。如果給出了?ignore missing?,且所有這些模板都不存在,會(huì)退化 至不做任何渲染,否則將會(huì)拋出一個(gè)異常。
例子:
{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
Changed in version 2.4:?如果傳遞一個(gè)模板對(duì)象到模板上下文,你可以用?include?包含這個(gè)對(duì) 象。
Jinja2 支持在宏中放置經(jīng)常使用的代碼。這些宏可以被導(dǎo)入,并不同的模板中使用。這 與 Python 中的 import 語句類似。要知道的是,導(dǎo)入量會(huì)被緩存,并且默認(rèn)下導(dǎo)入的 模板不能訪問當(dāng)前模板中的非全局變量。更多關(guān)于導(dǎo)入和包含的上下文行為見?導(dǎo)入上下文行為?。
有兩種方式來導(dǎo)入模板。你可以把整個(gè)模板導(dǎo)入到一個(gè)變量或從其中導(dǎo)入請(qǐng)求特定的宏 /導(dǎo)出量。
比如我們有一個(gè)渲染表單(名為?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 %}
最簡(jiǎn)單靈活的方式是把整個(gè)模塊導(dǎo)入為一個(gè)變量。這樣你可以訪問屬性:
{% 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>
名稱以一個(gè)或更多下劃線開始的宏和變量是私有的,不能被導(dǎo)入。
Changed in version 2.4:?如果傳遞一個(gè)模板對(duì)象到模板上下文,從那個(gè)對(duì)象中導(dǎo)入。
更多建議: