控制結構指的是所有的那些可以控制程序流的東西 —— 條件(比如 if/elif/ekse )、 for 循環、以及宏和塊之類的東西。控制結構在默認語法中以?{%?..?%}?塊的形式 出現。
### For[](http://docs.jinkan.org/docs/jinja2/templates.html#for "Permalink to this headline")
遍歷序列中的每項。例如,要顯示一個由?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 循環塊中你可以訪問這些特殊的變量:
| 變量 | 描述 |
| --- | --- |
| loop.index | 當前循環迭代的次數(從 1 開始) |
| loop.index0 | 當前循環迭代的次數(從 0 開始) |
| loop.revindex | 到循環結束需要迭代的次數(從 1 開始) |
| loop.revindex0 | 到循環結束需要迭代的次數(從 0 開始) |
| loop.first | 如果是第一次迭代,為 True 。 |
| loop.last | 如果是最后一次迭代,為 True 。 |
| loop.length | 序列中的項目數。 |
| loop.cycle | 在一串序列間期取值的輔助函數。見下面的解釋。 |
在 for 循環中,可以使用特殊的?loop.cycle?輔助函數,伴隨循環在一個字符串/變 量列表中周期取值:
~~~
{% for row in rows %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
~~~
從 Jinja 2.1 開始,一個額外的?cycle?輔助函數允許循環限定外的周期取值。 更多信息請閱讀?[*全局函數清單*](http://docs.jinkan.org/docs/jinja2/templates.html#builtin-globals)?。
與 Python 中不同,模板中的循環內不能?break?或?continue?。但你可以在迭代 中過濾序列來跳過項目。下面的例子中跳過了所有隱藏的用戶:
~~~
{% 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>
~~~
也可以遞歸地使用循環。當你處理諸如站點地圖之類的遞歸數據時很有用。要遞歸地 使用循環,你只需要在循環定義中加上?recursive?修飾,并在你想使用遞歸的地 方,對可迭代量調用?loop?變量。
下面的例子用遞歸循環實現了站點地圖:
~~~
<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[](http://docs.jinkan.org/docs/jinja2/templates.html#if "Permalink to this headline")
Jinja 中的?if?語句可比 Python 中的 if 語句。在最簡單的形式中,你可以測試 一個變量是否未定義,為空或 false:
~~~
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
~~~
像在 Python 中一樣,用?elif?和?else?來構建多個分支。你也可以用更復雜的?[*表達式*](http://docs.jinkan.org/docs/jinja2/templates.html#expressions):
~~~
{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
~~~
If 也可以被用作?[*內聯表達式*](http://docs.jinkan.org/docs/jinja2/templates.html#if-expression)?并作為?[*循環過濾*](http://docs.jinkan.org/docs/jinja2/templates.html#loop-filtering)?。
### 宏[](http://docs.jinkan.org/docs/jinja2/templates.html#id19 "Permalink to this headline")
宏類似常規編程語言中的函數。它們用于把常用行為作為可重用的函數,取代 手動重復的工作。
這里是一個宏渲染表單元素的小例子:
~~~
{% 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*](http://docs.jinkan.org/docs/jinja2/templates.html#import)?。
在宏內部,你可以訪問三個特殊的變量:
varargs
如果有多于宏接受的參數個數的位置參數被傳入,它們會作為列表的值保存在?varargs變量上。
kwargs
同?varargs?,但只針對關鍵字參數。所有未使用的關鍵字參數會存儲在 這個特殊變量中。
caller
如果宏通過?[*call*](http://docs.jinkan.org/docs/jinja2/templates.html#call)?標簽調用,調用者會作為可調用的宏被存儲在這個 變量中。
宏也可以暴露某些內部細節。下面的宏對象屬性是可用的:
name
宏的名稱。?{{?input.name?}}?會打印?input?。
arguments
一個宏接受的參數名的元組。
defaults
默認值的元組。
catch_kwargs
如果宏接受額外的關鍵字參數(也就是訪問特殊的?kwargs?變量),為?true?。
catch_varargs
如果宏接受額外的位置參數(也就是訪問特殊的?varargs?變量),為?true?。
caller
如果宏訪問特殊的?caller?變量且由?[*call*](http://docs.jinkan.org/docs/jinja2/templates.html#call)?標簽調用,為?true?。
如果一個宏的名稱以下劃線開始,它不是導出的且不能被導入。
### 調用[](http://docs.jinkan.org/docs/jinja2/templates.html#call "Permalink to this headline")
在某些情況下,需要把一個宏傳遞到另一個宏。為此,可以使用特殊的?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 %}
~~~
### 過濾器[](http://docs.jinkan.org/docs/jinja2/templates.html#id21 "Permalink to this headline")
過濾器段允許你在一塊模板數據上應用常規 Jinja2 過濾器。只需要把代碼用?filter?節包裹起來:
~~~
{% filter upper %}
This text becomes uppercase
{% endfilter %}
~~~
### 賦值[](http://docs.jinkan.org/docs/jinja2/templates.html#id22 "Permalink to this headline")
在代碼塊中,你也可以為變量賦值。在頂層的(塊、宏、循環之外)賦值是可導出的,即 可以從別的模板中導入。
賦值使用?set?標簽,并且可以為多個變量賦值:
~~~
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
~~~
### 繼承[](http://docs.jinkan.org/docs/jinja2/templates.html#id23 "Permalink to this headline")
extends?標簽用于從另一個模板繼承。你可以在一個文件中使用多次繼承,但是 只會執行其中的一個。見上面的關于?[*模板繼承*](http://docs.jinkan.org/docs/jinja2/templates.html#template-inheritance)?的節。
### 塊[](http://docs.jinkan.org/docs/jinja2/templates.html#id24 "Permalink to this headline")
塊用于繼承,同時作為占位符和用于替換的內容。?[*模板繼承*](http://docs.jinkan.org/docs/jinja2/templates.html#template-inheritance)?節中詳細地介紹了塊。
### 包含[](http://docs.jinkan.org/docs/jinja2/templates.html#id25 "Permalink to this headline")
include?語句用于包含一個模板,并在當前命名空間中返回那個文件的內容渲 染結果:
~~~
{% include 'header.html' %}
Body
{% include 'footer.html' %}
~~~
被包含的模板默認可以訪問活動的上下文中的變量。更多關于導入和包含的上下文 行為見[*導入上下文行為*](http://docs.jinkan.org/docs/jinja2/templates.html#import-visibility)?。
從 Jinja 2.2 開始,你可以把一句 include 用?ignore?missing?標記,這樣 如果模板不存在,Jinja 會忽略這條語句。當與?with?或?without?context?語句聯合使用時,它必須被放在上下文可見性語句?*之前*?。這里是一些有效的例 子:
~~~
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}
~~~
New in version 2.2.
你也可以提供一個模板列表,它會在包含前被檢查是否存在。第一個存在的模板會 被包含進來。如果給出了?ignore missing?,且所有這些模板都不存在,會退化 至不做任何渲染,否則將會拋出一個異常。
例子:
~~~
{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
~~~
Changed in version 2.4:?如果傳遞一個模板對象到模板上下文,你可以用?include?包含這個對 象。
### 導入[](http://docs.jinkan.org/docs/jinja2/templates.html#import "Permalink to this headline")
Jinja2 支持在宏中放置經常使用的代碼。這些宏可以被導入,并不同的模板中使用。這 與 Python 中的 import 語句類似。要知道的是,導入量會被緩存,并且默認下導入的 模板不能訪問當前模板中的非全局變量。更多關于導入和包含的上下文行為見?[*導入上下文行為*](http://docs.jinkan.org/docs/jinja2/templates.html#import-visibility)?。
有兩種方式來導入模板。你可以把整個模板導入到一個變量或從其中導入請求特定的宏 /導出量。
比如我們有一個渲染表單(名為?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>
~~~
名稱以一個或更多下劃線開始的宏和變量是私有的,不能被導入。
Changed in version 2.4:?如果傳遞一個模板對象到模板上下文,從那個對象中導入。
- 介紹
- 預備知識
- 安裝
- 基本 API 使用
- 實驗性的 Python 3 支持
- API
- 基礎
- Unicode
- 高層 API
- 自動轉義
- 標識符的說明
- 未定義類型
- 上下文
- 加載器
- 字節碼緩存
- 實用工具
- 異常
- 自定義過濾器
- 求值上下文
- 自定義測試
- 全局命名空間
- 低層 API
- 元 API
- 沙箱
- API
- 運算符攔截
- 模板設計者文檔
- 概要
- 變量
- 過濾器
- 測試
- 注釋
- 空白控制
- 轉義
- 行語句
- 模板繼承
- HTML 轉義
- 控制結構清單
- 導入上下文行為
- 表達式
- 內置過濾器清單
- 內置測試清單
- 全局函數清單
- 擴展
- 自動轉義擴展
- 擴展
- 添加擴展
- i18n 擴展
- 表達式語句
- 循環控制
- With 語句
- 自動轉義擴展
- 編寫擴展
- 集成
- Babel 集成
- Pylons
- TextMate
- Vim
- 從其它的模板引擎切換
- Jinja1
- Django
- Mako
- 提示和技巧
- Null-Master 退回
- 交替的行
- 高亮活動菜單項
- 訪問父級循環