範本設計師文件¶
本文檔描述了範本引擎的語法和語義,對於那些創建 Jinja 範本的人來說,它將是最有用的參考。由於範本引擎非常靈活,因此應用程序的配置在分隔符和未定義值的行為方面可能與此處顯示的代碼略有不同。
概要¶
Jinja 範本只是一個文字檔案。Jinja 可以生成任何基於文字的格式(HTML、XML、CSV、LaTeX 等)。Jinja 範本不需要有特定的副檔名:.html
、.xml
或任何其他副檔名都可以。
範本包含變數和/或表達式,它們在範本被渲染時會被值替換;以及標籤,它們控制範本的邏輯。範本語法很大程度上受到 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 分隔符配置如下
行語句和註釋 也是可能的,儘管它們沒有默認的前綴字符。要使用它們,請在創建 Environment
時設置 line_statement_prefix
和 line_comment_prefix
。
範本檔案副檔名¶
如上所述,任何檔案都可以作為範本加載,無論檔案副檔名如何。添加 .jinja
副檔名,例如 user.html.jinja
,可能會使某些 IDE 或編輯器插件更容易使用,但不是必需的。稍後介紹的自動轉義可以基於檔案副檔名應用,因此在這種情況下,您需要考慮額外的後綴。
另一個識別範本的好方法是它們位於 templates
文件夾中,無論副檔名如何。這是項目的常見佈局。
變數¶
範本變數由傳遞給範本的上下文字典定義。
您可以在範本中處理變數,前提是它們是由應用程序傳遞進來的。變數可能具有您可以訪問的屬性或元素。變數具有哪些屬性很大程度上取決於提供該變數的應用程序。
除了標準 Python __getitem__
“下標”語法 ([]
) 之外,您還可以點 (.
) 來訪問變數的屬性。
以下幾行做同樣的事情
{{ foo.bar }}
{{ foo['bar'] }}
重要的是要知道,外部的雙大括號不是變數的一部分,而是打印語句的一部分。如果您在標籤內訪問變數,請不要在它們周圍放置大括號。
如果變數或屬性不存在,您將獲得一個未定義的值。您可以對這種值做什麼取決於應用程序配置:默認行為是在打印或迭代時評估為空字符串,並在所有其他操作中失敗。
實作
為了方便起見,Jinja 中的 foo.bar
在 Python 層上執行以下操作
檢查
foo
上是否有稱為bar
的屬性 (getattr(foo, 'bar')
)如果沒有,請檢查
foo
中是否有項目'bar'
(foo.__getitem__('bar')
)如果沒有,則返回一個未定義的對象。
foo['bar']
的工作原理大致相同,但在順序上略有不同
檢查
foo
中是否有項目'bar'
。(foo.__getitem__('bar')
)如果沒有,請檢查
foo
上是否有稱為bar
的屬性。(getattr(foo, 'bar')
)如果沒有,則返回一個未定義的對象。
如果一個對象具有名稱相同的項目和屬性,這一點很重要。此外,attr()
過濾器僅查找屬性。
過濾器¶
變數可以通過過濾器修改。過濾器通過管道符號 (|
) 與變數分隔,並且可以在括號中包含可選參數。多個過濾器可以鏈接在一起。一個過濾器的輸出應用於下一個過濾器。
例如,{{ name|striptags|title }}
將從變數 name
中刪除所有 HTML 標籤,並將輸出標題化 (title(striptags(name))
)。
接受參數的過濾器在參數周圍有括號,就像函數調用一樣。例如:{{ listx|join(', ') }}
將使用逗號連接列表 (str.join(', ', listx)
)。
下面的 內建過濾器列表 描述了所有內建過濾器。
測試¶
除了過濾器之外,還有所謂的「測試」。測試可以用來根據通用表達式測試變數。要測試變數或表達式,您可以在變數後面加上 is
以及測試的名稱。例如,要判斷變數是否已定義,您可以執行 name is defined
,這將根據 name
是否在目前的模板上下文中定義而返回 true 或 false。
測試也可以接受參數。如果測試只接受一個參數,則可以省略括號。例如,以下兩個表達式執行相同的操作
{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}
下面的 內建測試列表 描述了所有內建測試。
空白控制¶
在預設配置中
如果存在單個尾隨換行符,則會將其刪除
其他空白(空格、製表符、換行符等)將保持不變
如果應用程式將 Jinja 配置為 trim_blocks
,則模板標籤後的第一個換行符將自動刪除(如 PHP 中)。也可以設定 lstrip_blocks
選項,以從行首到區塊開頭刪除製表符和空格。(如果區塊開頭之前還有其他字元,則不會刪除任何內容。)
啟用 trim_blocks
和 lstrip_blocks
後,您可以將區塊標籤放在自己的行上,並且在渲染時將刪除整個區塊行,同時保留內容的空白。例如,如果沒有 trim_blocks
和 lstrip_blocks
選項,則此模板
<div>
{% if True %}
yay
{% endif %}
</div>
在 div 內渲染時會出現空行
<div>
yay
</div>
但是,啟用 trim_blocks
和 lstrip_blocks
後,模板區塊行將被刪除,其他空白將被保留
<div>
yay
</div>
您可以通過在區塊開頭放置一個加號 (+
) 來手動禁用 lstrip_blocks
行為
<div>
{%+ if something %}yay{% endif %}
</div>
同樣,您可以通過在區塊結尾放置一個加號 (+
) 來手動禁用 trim_blocks
行為
<div>
{% if something +%}
yay
{% endif %}
</div>
您也可以手動刪除模板中的空白。如果在區塊(例如 For 標籤)、註釋或變數表達式的開頭或結尾添加減號 (-
),則該區塊之前或之後的空白將被刪除
{% for item in seq -%}
{{ item }}
{%- endfor %}
這將產生所有元素之間沒有空格的輸出。如果 seq
是從 1
到 9
的數字列表,則輸出將是 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>
只要前面沒有文字,行語句前綴就可以出現在行中的任何位置。為了提高可讀性,啟動區塊的語句(例如 for
、if
、elif
等)可以以冒號結尾
# 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 起,也提供了基於行的註釋。例如,如果行註釋前綴配置為 ##
,則從 ##
到行尾的所有內容都將被忽略(不包括換行符)
# 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 %}
© 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 %}
標籤是關鍵所在。它告訴模板引擎此模板「繼承」了另一個模板。當模板系統評估此模板時,它首先會找到父模板。 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¶
在多層 {% 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.
區塊嵌套和作用域¶
可以嵌套區塊以實現更複雜的佈局。但是,默認情況下,區塊可能無法訪問外部作用域中的變數
{% 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.txt
或 issue.txt
將引發 TemplateRuntimeError
,因為它們沒有覆蓋 body
區塊。渲染 bug_report.txt
將成功,因為它確實覆蓋了該區塊。
與 scoped
結合使用時,required
修飾符必須放置在 scoped 修飾符*之後*。以下是一些有效的示例
{% block body scoped %}{% endblock %}
{% block body required %}{% endblock %}
{% block body scoped required %}{% endblock %}
模板對象¶
extends
、include
和 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 的字符的風險。有兩種方法
手動轉義每個變數;或者
默認情況下自動轉義所有內容。
Jinja 支持這兩種方法。使用哪種方法取決於應用程式配置。默認配置是不自動轉義;原因有很多
轉義除安全值之外的所有內容也意味著 Jinja 會轉義已知不包含 HTML 的變數(例如數字、布爾值),這可能會導致巨大的性能損失。
有關變數安全性的信息非常脆弱。可能會發生這樣的情況:通過強制安全值和不安全值,返回值是雙重轉義的 HTML。
使用手動轉義¶
如果啟用了手動跳脫,則在需要時跳脫變數是您的責任。 要跳脫什麼? 如果您的變數可能包含以下任何字元(>
、<
、&
或 "
),您應該跳脫它,除非該變數包含格式正確且受信任的 HTML。 跳脫的工作原理是通過 |e
过滤器管道傳輸變數
{{ user.username|e }}
使用自動跳脫¶
啟用自動跳脫時,除了明確標記為安全的數值外,其他所有內容都會默認被跳脫。 變數和表達式可以通過以下方式標記為安全:
應用程序使用
markupsafe.Markup
在上下文字典中標記在模板中,使用
|safe
过滤器標記。
如果您標記為安全的字串通過其他不理解該標記的 Python 代码,則該標記可能會遺失。 請注意您的數據何時被標記為安全以及在到達模板之前是如何處理的。
如果一個數值已被跳脫但未標記為安全,則自動跳脫仍將發生,並導致字符被雙重跳脫。 如果您知道您的數據已經安全但未標記,請務必將其包裝在 Markup
中或使用 |safe
过滤器。
Jinja 函數(宏、super
、self.BLOCKNAME
)始終返回標記為安全的模板數據。
具有自動跳脫功能的模板中的字串字面量被認為是不安全的,因為原生 Python 字串是不安全的。
控制結構列表¶
控制結構指的是所有控制程序流程的事物 - 條件語句(即 if/elif/else)、for 迴圈,以及宏和塊之類的事物。 使用默認語法,控制結構會出現在 {% ... %}
塊內。
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.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 迴圈塊內,您可以訪問一些特殊的變數
變數 |
說明 |
---|---|
|
迴圈的當前迭代次數。(從 1 開始計數) |
|
迴圈的當前迭代次數。(從 0 開始計數) |
|
從迴圈結尾開始的迭代次數(從 1 開始計數) |
|
從迴圈結尾開始的迭代次數(從 0 開始計數) |
|
如果是第一次迭代,則為 True。 |
|
如果是最後一次迭代,則為 True。 |
|
序列中的項目數。 |
|
一個輔助函數,用於在序列列表之間循環。 請參閱下面的說明。 |
|
指示當前渲染在遞迴迴圈中的深度。 從級別 1 開始 |
|
指示當前渲染在遞迴迴圈中的深度。 從級別 0 開始 |
|
迴圈上一次迭代的項目。 在第一次迭代期間未定義。 |
|
迴圈下一次迭代的項目。 在最後一次迭代期間未定義。 |
|
如果先前使用不同的數值調用(或根本未調用),則為 True。 |
在 for 迴圈中,每次通過迴圈時,都可以使用特殊的 loop.cycle
輔助函數在字串/變數列表之間循環
{% for row in rows %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
自 Jinja 2.1 起,存在一個額外的 cycle
輔助函數,允許迴圈無關的循環。 有關更多信息,請查看全局函數列表。
與 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>
請注意,在 Python 中,只要相應的迴圈沒有執行 break
,就會執行 else
塊。 由於 Jinja 迴圈無論如何都不能執行 break
,因此選擇了 else
關鍵字的略微不同的行為。
也可以遞迴使用迴圈。 如果您正在處理遞迴數據(例如網站地圖或 RDFa),這將很有用。 要遞迴使用迴圈,您基本上必須將 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>
loop
變數始終指的是最接近的(最內層)迴圈。 如果我們有多個级别的迴圈,我們可以在我們想要遞迴使用的迴圈之後通過編寫 {% set outer_loop = loop %}
來重新綁定變數 loop
。 然後,我們可以使用 {{ outer_loop(...) }}
調用它
請注意,迴圈中的賦值將在迭代結束時清除,並且不能超出迴圈範圍。 舊版本的 Jinja 中存在一個錯誤,在某些情況下,賦值似乎可以工作。 這不受支持。 有關如何處理此問題的更多信息,請參閱賦值。
如果您只想檢查自上次迭代以來某些數值是否已更改或在下一次迭代中是否會更改,則可以使用 previtem
和 nextitem
{% 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 中的 if
語句與 Python if 語句相當。 在最簡單的形式中,您可以使用它來測試變數是否已定義、是否為空以及是否為 false
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
對於多個分支,可以使用類似 Python 中的 elif
和 else
。您也可以在那裡使用更複雜的 運算式。
{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
巨集¶
巨集類似於一般程式語言中的函式。它們用於將常用的程式碼片段放入可重複使用的函式中,以避免重複程式碼(“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>
如果巨集是在不同的模板中定義的,則必須先 匯入 它。
在巨集內部,您可以存取三個特殊變數
varargs
如果傳遞給巨集的位置引數多於巨集接受的數量,則它們會以值列表的形式存儲在特殊變數
varargs
中。kwargs
類似於
varargs
,但用於關鍵字引數。所有未使用的關鍵字引數都存儲在此特殊變數中。caller
如果巨集是從 call 標籤呼叫的,則呼叫者會以可呼叫巨集的形式存儲在此變數中。
巨集還會公開一些內部細節。巨集物件上可以使用以下屬性
name
巨集的名稱。
{{ input.name }}
將會印出input
。arguments
巨集接受的引數名稱的元組。
catch_kwargs
如果巨集接受額外的關鍵字引數(即:存取特殊變數
kwargs
),則此值為true
。catch_varargs
如果巨集接受額外的 positional 引數(即:存取特殊變數
varargs
),則此值為true
。caller
如果巨集存取特殊變數
caller
且可以從 call 標籤呼叫,則此值為true
。
如果巨集名稱以下劃線開頭,則不會匯出它,也不能匯入它。
由於 Jinja 中作用域的工作方式,子模板中的巨集不會覆蓋父模板中的巨集。以下將輸出“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 }}
請注意,set
標籤中的 obj.attr
符號僅允許用於命名空間物件;嘗試在任何其他物件上指派屬性將會引發異常。
更新日誌
新增於版本 2.10:新增對命名空間物件的支援
區塊指派¶
更新日誌
新增於版本 2.8。
從 Jinja 2.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 goes here.
{% include 'footer.html' %}
內含的模板預設可以存取目前模板的上下文。使用 without context
來改用獨立的上下文。 with context
也是有效的,但這是預設行為。請參閱 匯入上下文行為。
內含的模板可以 extend
另一個模板並覆寫該模板中的區塊。然而,目前的模板無法覆寫內含模板輸出的任何區塊。
使用 ignore missing
如果模板不存在則忽略該語句。它必須放在上下文可見性語句的 *前面*。
{% 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>
以一個或多個底線開頭的巨集和變數是私有的,無法匯入。
更新日誌
2.4 版的變更: 如果將模板物件傳遞給模板上下文,則可以從該物件匯入。
匯入上下文行為¶
預設情況下,內含的模板會傳遞目前的上下文,而匯入的模板則不會。這樣做的原因是,與內含不同,匯入會被快取;因為匯入通常僅用作存放巨集的模組。
可以明確地更改此行為:通過在 import/include 指令中添加 with context
或 without context
,可以將目前的上下文傳遞給模板,並且自動禁用快取。
以下是兩個例子
{% 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 允許在任何地方使用基本運算式。這些運算式的運作方式與一般的 Python 非常相似;即使您沒有使用 Python,您也應該能夠輕鬆上手。
字面量¶
最簡單的運算式形式是字面量。字面量是 Python 物件(例如字串和數字)的表示形式。存在以下字面量
"Hello World"
兩個雙引號或單引號之間的所有內容都是字串。每當您在模板中需要字串時,它們都很有用(例如,作為函數呼叫和過濾器的參數,或者只是為了擴展或內含模板)。
42
/123_456
整數是沒有小數部分的整數。「_」字元可用於分隔群組以提高可讀性。
42.23
/42.1e2
/123_456.789
浮點數可以使用「.」作為小數點來書寫。它們也可以用科學記數法書寫,使用大寫或小寫的「e」來表示指數部分。「_」字元可用於分隔群組以提高可讀性,但不能在指數部分使用。
['list', 'of', 'objects']
兩個括號之間的所有內容都是列表。列表可用於儲存要迭代的序列資料。例如,您可以使用列表和元組輕鬆地建立連結列表,並使用 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 中的字典是一種將鍵和值組合在一起的結構。鍵必須是唯一的,並且始終只有一個值。字典很少在模板中使用;它們在某些少數情況下很有用,例如
xmlattr()
過濾器。true
/false
true
始終為真,false
始終為假。
注意
特殊常數 true
、false
和 none
確實是小寫的。因為這在過去造成了混淆(True
過去會擴展為被認為是假的未定義變數),所以現在這三個常數也可以用標題大小寫書寫(True
、False
和 None
)。但是,為了保持一致性(所有 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 }}
在 Jinja 中會被計算為(3**3)**3
,但在 Python 中會被計算為3**(3**3)
。在 Jinja 中使用括號來明確指定您想要的順序。通常最好在 Python 中進行擴展數學運算,並將結果傳遞給render
,而不是在模板中進行。如果可以引入升級路徑,則此行為可能會在將來更改以匹配 Python。
比較¶
==
比較兩個物件是否相等。
!=
比較兩個物件是否不相等。
>
如果左側大於右側,則為
true
。>=
如果左側大於或等於右側,則為
true
。<
如果左側小於右側,則為
true
。<=
如果左側小於或等於右側,則為
true
。
邏輯¶
對於 if
語句、for
篩選和 if
表達式,組合多個表達式可能很有用
and
如果左運算元和右運算元都為 true,則返回 true。
or
如果左運算元或右運算元為 true,則返回 true。
not
否定一個語句(見下文)。
(expr)
括號將一個表達式分組。
注意
is
和 in
運算符也支援使用中綴符號進行否定:foo is not bar
和 foo not in bar
,而不是 not foo is bar
和 not foo in bar
。所有其他表達式都需要使用前綴符號:not (foo and bar).
其他運算符¶
以下運算符非常有用,但不屬於其他兩個類別中的任何一個
in
執行序列/映射包含測試。如果左運算元包含在右運算元中,則返回 true。
{{ 1 in [1, 2, 3] }}
例如將返回 true。is
執行測試。
|
(管道符號,豎線)套用篩選器。
~
(波浪號)將所有運算元轉換為字串並將它們連接起來。
{{ "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' %}
一般語法是 <做某事> if <某事為真> else <做其他事>
。
else
部分是可選的。如果未提供,則 else 塊將隱式計算為 Undefined
物件(無論環境中的 undefined
設定為何)
{{ "[{}]".format(page.title) if page.title }}
Python 方法¶
您也可以使用在變數類型上定義的任何方法。從方法調用返回的值將用作表達式的值。以下是一個使用在字串上定義的方法的示例(其中 page.title
是一個字串)
{{ page.title.capitalize() }}
這適用於使用者自定義類型上的方法。例如,如果類型為 Foo
的變數 f
上定義了一個方法 bar
,則您可以執行以下操作
{{ f.bar(value) }}
運算符方法也能如預期般運作。例如,%
對字串實現了 printf 風格的格式化
{{ "Hello, %s!" % name }}
儘管您應該更喜歡使用 .format
方法來處理這種情況(在渲染模板的上下文中有點做作)
{{ "Hello, {}!".format(name) }}
內建過濾器列表¶
- jinja-filters.abs(x, /)¶
傳回引數的絕對值。
- jinja-filters.attr(obj: Any, name: str) jinja2.runtime.Undefined | Any ¶
取得物件的屬性。
foo|attr("bar")
的作用類似於foo.bar
,只是它總是傳回一個屬性,並且不會查找項目。有關更多詳細資訊,請參閱 關於訂閱的注意事項。
- 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, ' ') %} <tr> {%- for column in row %} <td>{{ column }}</td> {%- endfor %} </tr> {%- endfor %} </table>
- jinja-filters.default(value: V, default_value: V = '', boolean: bool = False) V ¶
如果值未定義,則會傳回傳入的預設值,否則會傳回變數的值
{{ my_variable|default('my_variable is not defined') }}
如果定義了變數,則會輸出
my_variable
的值,否則會輸出my_variable 未定義
。如果您想將 default 與評估為 false 的變數一起使用,則必須將第二個參數設定為true
{{ ''|default('the string was empty', true) }}
更新日誌
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 – 要轉換為字串並進行跳脫的物件。
- 傳回值:
包含跳脫文字的
Markup
字串。- 別名:
e
- jinja-filters.filesizeformat(value: str | float | int, binary: bool = False) str ¶
將值格式化為「人類可讀」的檔案大小(例如 13 kB、4.1 MB、102 Bytes 等)。預設情況下使用十進位字首(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 風格 的格式化字串,例如
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
不同,值會先排序,因此每個唯一值只會返回一個群組。例如,可以將具有
city
屬性的User
物件列表以群組呈現。在此範例中,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)
的 namedtuples,可以代替上面的元組解包使用。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
參數。排序和分組預設不區分大小寫,與其他進行比較的篩選器相符。更新日誌
在版本 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 – 不要跳過縮排空行。
更新日誌
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]] ¶
傳回映射的
(鍵, 值)
項的迭代器。x|items
與x.items()
相同,但如果x
未定義,則會傳回空迭代器。如果您預期範本會使用另一種程式語言中的 Jinja 實作來呈現,而該語言的映射類型沒有
.items()
方法,則此篩選器會很有用。<dl> {% for key, value in my_dict|items %} <dt>{{ key }} <dd>{{ value }} {% endfor %} </dl>
3.1 版新增。
- jinja-filters.join(value: Iterable[Any], d: str = '', attribute: str | int | NoneType = None) str ¶
傳回一個字串,它是序列中字串的串聯。元素之間的分隔符號預設為空字串,您可以使用可選參數定義它
{{ [1, 2, 3]|join('|') }} -> 1|2|3 {{ [1, 2, 3]|join }} -> 123
也可以加入物件的某些屬性
{{ users|join(', ', attribute='username') }}
更新日誌
2.6 版新增: 新增了
attribute
參數。
- jinja-filters.last(seq: 't.Reversible[V]') 't.Union[V, Undefined]' ¶
傳回序列的最後一個項目。
注意:不適用於產生器。您可能需要將其明確轉換為清單
{{ data | selectattr('name', '==', 'Jinja') | list | last }}
- jinja-filters.length(obj, /)¶
傳回容器中的項目數。
- 別名:
計數
- jinja-filters.list(value: 't.Iterable[V]') 't.List[V]' ¶
將值轉換為清單。如果它是字串,則傳回的清單將是字元清單。
- jinja-filters.map(value: Iterable[Any], *args: Any, **kwargs: Any) Iterable[Any] ¶
將篩選器應用於物件序列或查找屬性。當處理物件列表但您實際上只對其中某個值感興趣時,這會很有用。
基本用法是映射到屬性。想像您有一個使用者列表,但您只對使用者名稱列表感興趣
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)
更新日誌
版本 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.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))
更新日誌
新增於版本 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))
更新日誌
新增於版本 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.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.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))
更新日誌
新增於版本 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))
更新日誌
新增於版本 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 %}
更新日誌
在版本 2.11.0 中更改:
attribute
參數可以是逗號分隔的屬性列表,例如"age,name"
。在版本 2.6 中更改: 添加了
attribute
參數。
- jinja-filters.string(value)¶
如果對象不是字符串,則將其轉換為字符串。這會保留
Markup
字符串而不是將其轉換回基本字符串,因此它仍然會被標記為安全並且不會再次被轉義。>>> value = escape("<User 1>") >>> value Markup('<User 1>') >>> escape(str(value)) Markup('&lt;User 1&gt;') >>> escape(soft_str(value)) Markup('<User 1>')
- jinja-filters.sum(iterable: 't.Iterable[V]', attribute: str | int | NoneType = None, start: V = 0) V ¶
返回數字序列的總和加上參數“start”的值(默认为 0)。當序列為空時,它返回 start。
也可以只對某些屬性求和
Total: {{ items|sum(attribute='price') }}
更新日誌
在版本 2.6 中更改: 添加了
attribute
參數以允許對屬性求和。此外,start
參數也向右移動了。
- jinja-filters.tojson(value: Any, indent: int | None = None) markupsafe.Markup ¶
將物件序列化為 JSON 字串,並標記為可在 HTML 中安全地呈現。此過濾器僅適用於 HTML 文件。
傳回的字串可以在 HTML 文件和
<script>
標籤中安全地呈現。例外情況是在使用雙引號的 HTML 屬性中;請使用單引號或|forceescape
過濾器。- 參數:
value – 要序列化為 JSON 的物件。
indent – 傳遞給
dumps
的indent
參數,用於漂亮地列印值。
更新日誌
新增於版本 2.9。
- 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]' ¶
從給定的可迭代對象返回唯一項目的列表。
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }} -> ['foo', 'bar', 'foobar']
唯一項目的產生順序與它們在傳遞給過濾器的可迭代對象中的第一次出現順序相同。
- 參數:
case_sensitive – 將大小寫字串視為不同的字串。
attribute – 篩選具有此屬性唯一值的物件。
- jinja-filters.urlencode(value: str | Mapping[str, Any] | Iterable[Tuple[str, Any]]) str ¶
使用 UTF-8 編碼網址路徑或查詢字串資料。
當給定字串時,這是
urllib.parse.quote()
的基本包裝器,或者當給定字典或可迭代物件時,這是urllib.parse.urlencode()
的基本包裝器。- 參數:
value – 要編碼的資料。字串將會直接被編碼。字典或
(鍵, 值)
對的可迭代物件將會被連接成查詢字串。
當給定字串時,「/」不會被編碼。HTTP 伺服器在路徑中將「/」和「%2F」視為等效。如果您需要編碼斜線,請使用
|replace("/", "%2F")
篩選器。更新日誌
新增於版本 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 ¶
將文字中的網址轉換成可點擊的連結。
在某些情況下,這可能無法識別連結。通常,更全面的格式化工具(例如 Markdown 函式庫)是更好的選擇。
適用於
http://
、https://
、www.
、mailto:
和電子郵件地址。識別具有尾隨標點符號(句點、逗號、右括號)和前導標點符號(左括號)的連結,但不包括標點符號。不識別包含標頭欄位的電子郵件地址(例如,mailto:address@example.com?cc=copy@example.com
)。- 參數:
value – 包含要連結之網址的原始文字。
trim_url_limit – 將顯示的網址值縮短至此長度。
nofollow – 將
rel=nofollow
屬性添加到連結。target – 將
target
屬性添加到連結。rel – 將
rel
屬性添加到連結。extra_schemes – 除了預設行為外,還可以識別以這些協定開頭的網址。預設為
env.policies["urlize.extra_schemes"]
,預設為沒有額外的協定。
更新日誌
3.0 版的變更: 新增了
extra_schemes
參數。3.0 版的變更: 為沒有協定的網址產生
https://
連結。3.0 版的變更: 更新了剖析規則。識別有無
mailto:
協定的電子郵件地址。驗證 IP 地址。在更多情況下忽略括號和方括號。2.8 版的變更: 新增了
target
參數。
- 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
。
更新日誌
在版本 2.11 中更改: 現有的換行符號會被視為段落分別換行。
在版本 2.11 中更改: 新增了
break_on_hyphens
參數。在版本 2.7 中更改: 新增了
wrapstring
參數。
- jinja-filters.xmlattr(d: Mapping[str, Any], autospace: bool = True) str ¶
根據字典中的項目建立 SGML/XML 屬性字串。
非
none
或undefined
的值會自動跳脫,安全地允許不受信任的使用者輸入。不應將使用者輸入作為此篩選器的鍵值。如果任何鍵值包含空格、
/
斜線、>
大於符號或=
等於符號,則會因ValueError
而失敗。無論如何,不應將使用者輸入作為此篩選器的鍵值,或者必須先另外驗證。<ul{{ {'class': 'my_list', 'missing': none, 'id': 'list-%d'|format(variable)}|xmlattr }}> ... </ul>
結果如下所示
<ul class="my_list" id="list-42"> ... </ul>
如您所見,如果篩選器傳回某些內容,它會自動在項目前面加上空格,除非第二個參數為 false。
在版本 3.1.4 中更改: 不允許使用包含
/
斜線、>
大於符號或=
等於符號的鍵值。在版本 3.1.3 中更改: 不允許使用包含空格的鍵值。
內建測試列表¶
- jinja-tests.callable(obj, /)¶
傳回物件是否可呼叫(即某種函數)。
請注意,類別是可呼叫的,具有 __call__() 方法的類別實例也是可呼叫的。
- jinja-tests.defined(value: Any) bool ¶
如果變數已定義,則傳回 true
{% if variable is defined %} value of variable: {{ variable }} {% else %} variable is not defined {% endif %}
請參閱
default()
篩選器,了解設定未定義變數的簡單方法。
- jinja-tests.eq(a, b, /)¶
與 a == b 相同。
- 別名:
==
,equalto
- jinja-tests.filter(value: str) bool ¶
按名稱檢查篩選器是否存在。如果篩選器可能可選可用,則很有用。
{% if 'markdown' is filter %} {{ value | markdown }} {% else %} {{ value }} {% endif %}
更新日誌
版本 3.0 中新增。
- jinja-tests.ge(a, b, /)¶
與 a >= b 相同。
- 別名:
>=
- jinja-tests.gt(a, b, /)¶
與 a > b 相同。
- 別名:
>
,greaterthan
- jinja-tests.le(a, b, /)¶
與 a <= b 相同。
- 別名:
<=
- jinja-tests.lt(a, b, /)¶
與 a < b 相同。
- 別名:
<
,lessthan
- jinja-tests.ne(a, b, /)¶
與 a != b 相同。
- 別名:
!=
- jinja-tests.sameas(value: Any, other: Any) bool ¶
檢查物件是否指向與另一個物件相同的記憶體位址
{% if foo.attribute is sameas false %} the foo attribute really is the `False` singleton {% endif %}
全局函數列表¶
以下函數在全局範圍內默認可用
- 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 範例文字。默認情況下,會生成五個 HTML 段落,每個段落包含 20 到 100 個字。如果 html 為 False,則返回純文本。這對於生成用於佈局測試的簡單內容很有用。
- jinja-globals.dict(\**items)¶
字典字面量的便捷替代方案。
{'foo': 'bar'}
與dict(foo='bar')
相同。
- class jinja-globals.cycler(\*items)¶
通過一次產生一個值來循環遍歷值,然後在到達末尾時重新開始。
類似於
loop.cycle
,但可以在循環外或跨多個循環使用。例如,在列表中渲染文件夾和文件的列表,交替給它們 “odd” 和 “even” 類別。{% 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 – 每個位置參數將按照每個循環給定的順序產生。
更新日誌
新增於 2.1 版。
- reset()¶
將當前項目重置為第一個項目。
- class jinja-globals.joiner(sep=', ')¶
一個可以用於“連接”多個部分的小幫手。每次調用 joiner 時,它都會傳入一個字符串並返回該字符串,但第一次除外(在這種情況下,它返回一個空字符串)。你可以使用它來連接東西
{% 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 jinja-globals.namespace(...)¶
創建一個新的容器,允許使用
{% set %}
標籤進行屬性賦值{% set ns = namespace() %} {% set ns.foo = 'bar' %}
這樣做的主要目的是允許將值從循環體內部攜帶到外部作用域。初始值可以作為字典、關鍵字參數或兩者一起提供(與 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 中新增。
擴充功能¶
以下章節涵蓋了可能由應用程序啟用的內建 Jinja 擴充功能。應用程序也可以提供本文檔未涵蓋的其他擴充功能;在這種情況下,應有另一份文件說明所述 擴充功能。
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 book_title=book.title %}
This is {{ book_title }}.
You should read it!
{% endtrans %}
這會在翻譯文件中產生 這 是 %(book_title)s。 您 應該 閱讀 它!
。
如果全局啟用了修剪,則可以使用 notrimmed
修飾符為區塊禁用它。
更新日誌
2.10 版新增: 已添加 trimmed
和 notrimmed
修飾符。
如果翻譯取決於訊息出現的上下文,則 pgettext
和 npgettext
函數會將 context
字串作為第一個參數,用於選擇適當的翻譯。要使用 {% trans %}
標籤指定上下文,請在 trans
之後提供一個字串作為第一個標記。
{% trans "fruit" %}apple{% endtrans %}
{% trans "fruit" trimmed count -%}
1 apple
{%- pluralize -%}
{{ count }} apples
{%- endtrans %}
3.1 版新增: 可以將上下文傳遞給 trans
標籤以使用 pgettext
和 npgettext
。
可以使用以下函數翻譯表達式中的字串
_(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') %}
迴圈控制¶
如果應用程式啟用了 迴圈控制,則可以在迴圈中使用 break
和 continue
。當到達 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 開始(請參閱:For)。
除錯語句¶
如果啟用了 除錯擴展,則可以使用 {% 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']}
With 語句¶
更新日誌
2.3 版新增。
with 語句可以創建一個新的內部作用域。在此作用域內設置的變數在作用域外不可見。
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 區塊的開頭語句中定義的另一個變數。這導致了清理作用域行為的問題,並且此後得到了改進。特別是在較新的 Jinja 版本中,以下程式碼始終引用 with 區塊外部的變數 a
{% 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 之前)中,需要使用擴展來啟用此功能。現在它預設啟用。
註釋¶
要在模板中將部分行註釋掉,請使用註釋語法,預設設定為
{# ... #}
。這對於在除錯時註釋掉模板的某些部分或為其他模板設計師或您自己添加資訊非常有用