本頁(yè)回答了一些關(guān)于 Jinja 的常見(jiàn)問(wèn)題。
選擇 Jinja 作為名字是因?yàn)?Jinja 是日本寺廟的名稱,并且 temple 和 template 的發(fā)音類似。它并不是以烏干達(dá)的金賈市(Jinja)命名的。
我們相當(dāng)厭煩基準(zhǔn)測(cè)試,尤其是因?yàn)樗鼈儾⒉荒苡绊懯裁础R粋€(gè)模板的性能取決于許多因 素,而你可能需要在不同環(huán)境中對(duì)不同的引擎做基準(zhǔn)測(cè)試。測(cè)試套件中的基準(zhǔn)測(cè)試表明, Jinja2 與 Mako 的性能相近,比 Django 的模板引擎或 Genshi 快 10 到 20 倍。這 些數(shù)字應(yīng)該相當(dāng)有刺激性,因?yàn)榛鶞?zhǔn)測(cè)試只測(cè)試一些性能相關(guān)的場(chǎng)景,比如循環(huán),來(lái)獲取 這些數(shù)字。大體上,一個(gè)模板引擎的性能幾乎不會(huì)成為一個(gè) web 應(yīng)用的瓶頸,而應(yīng)該是 數(shù)據(jù)庫(kù)或應(yīng)用的代碼。
Jinja2 的語(yǔ)法與 Django 的語(yǔ)法很多都匹配。但這并不意味著你可以直接在 Jinja2 中原封不動(dòng)地使用 Django 模板。例如過(guò)濾器參數(shù)使用函數(shù)調(diào)用語(yǔ)法而不是用冒號(hào)分 隔過(guò)濾器名和參數(shù)。此外, Jinja 中的擴(kuò)展接口與 Django 的有根本區(qū)別,這意味著 你的自定義標(biāo)簽不能再正常工作。
總體而言,因?yàn)?Jinja 模板系統(tǒng)允許你使用一個(gè) Python 表達(dá)式的特定子集,你 會(huì)使用相當(dāng)少的自定義擴(kuò)展,且可以替代大多數(shù)的 Django 擴(kuò)展。例如,不是用下 面的這樣:
{% load comments %}
{% get_latest_comments 10 as latest_comments %}
{% for comment in latest_comments %}
...
{% endfor %}
你會(huì)更可能提供一個(gè)對(duì)象,用屬性來(lái)檢索數(shù)據(jù)庫(kù)中的評(píng)論:
{% for comment in models.comments.latest(10) %}
...
{% endfor %}
或直接為快速測(cè)試提供模型:
{% for comment in Comment.objects.order_by('-pub_date')[:10] %}
...
{% endfor %}
請(qǐng)記住即使你能在模板中放置這樣的東西,這也不是一個(gè)好主意。查詢應(yīng)該在視圖代 碼中執(zhí)行,而不是模板中!
毫無(wú)疑問(wèn),你應(yīng)該盡可能把邏輯從模板中移除。但沒(méi)有邏輯的模板意味著你不得不 在代碼中做所有的處理,而這是無(wú)趣和愚蠢的。一個(gè)如此做的支持 Python 的模板引 擎名為 string.Template ,它沒(méi)有循環(huán)和 if 條件,且是迄今為止你可以在 Python 中使用的最快的模板引擎。
所以模板中某種數(shù)量的邏輯會(huì)讓你愉悅。而且 Jinja 把要在模板中放置多少邏輯的問(wèn) 題幾乎都留給你了。這里有一些你可以做和不可以做的限制。
Jinaja2 不允許你在模板中放置任意的 Python 代碼,也不允許全部的 Python 表達(dá) 式。操作符限定為最常用的那些,且不支持諸如列表推導(dǎo)式和生成器表達(dá)式等高級(jí)表 達(dá)式。這使得模板引擎易于維護(hù),并且模板有更好的可讀性。
之所以自動(dòng)轉(zhuǎn)義不是默認(rèn)的模式,且不是推薦的模式有許多原因。自動(dòng)轉(zhuǎn)義變量意 味著你不再會(huì)面臨 XSS 問(wèn)題,它也導(dǎo)致在模板引擎中導(dǎo)致巨大規(guī)模的額外處理和嚴(yán) 重的性能問(wèn)題。因?yàn)?Python 不提供標(biāo)記字符串為不安全的方式, Jinja 提供了一 個(gè)自定義的字符串類( Markup 字符串)hack 這個(gè)限制來(lái)與安全和不安 全的字符串交互。
在顯式的轉(zhuǎn)義中,無(wú)論如何模板引擎都不需要運(yùn)行對(duì)變量的任何安全檢查。同樣,一 個(gè)自然人知道不去轉(zhuǎn)義永遠(yuǎn)不會(huì)包含需要轉(zhuǎn)義的或先前的 HTML 標(biāo)記的整數(shù)和字符串。 例如,當(dāng)在一個(gè)整數(shù)和浮點(diǎn)數(shù)的表中迭代時(shí),根據(jù)表的狀況,模板設(shè)計(jì)者可以略過(guò)轉(zhuǎn) 義,因?yàn)樗勒麛?shù)和浮點(diǎn)數(shù)不包含任何不安全的參數(shù)。
此外, Jinja2 是一個(gè)通用模板引擎,且不只用于 HTML/XML 生成。例如你會(huì)生成 LaTeX 、 郵件 、 CSS 、 JavaScript 或是配置文件。
當(dāng)寫(xiě) contextfunction() 或類似的東西時(shí),你可能會(huì)注意到上下文試圖阻止 你修改它。如果你已經(jīng)設(shè)法用內(nèi)部的上下文 API 修改了上下文,你會(huì)注意到上下文 上發(fā)生的修改在模板中是不可見(jiàn)的。這個(gè)的原因是 Jinja 為性能因素,只把上下文 作為模板變量的主要數(shù)據(jù)源。
如果你想要修改上下文,寫(xiě)一個(gè)函數(shù)返回一個(gè)變量,并用 set 賦值:
{% set comments = get_latest_comments() %}
要用在自動(dòng)轉(zhuǎn)義開(kāi)啟的情況下實(shí)現(xiàn)高性能,在老版本的 Jinja2 中轉(zhuǎn)義函數(shù)也需要用純 C 實(shí)現(xiàn),如果 Jinja2 與加速模塊一同安裝也會(huì)使用它。
因?yàn)檫@個(gè)特性本身對(duì)非模板引擎也很有用,它被移動(dòng)到 PyPI 上的一個(gè)獨(dú)立的項(xiàng) 目,名為 [MarkupSafe][2] 。
Jinja2 不再伴隨一個(gè) C 實(shí)現(xiàn)而是純粹的 Python 實(shí)現(xiàn)。無(wú)論如何,它會(huì)檢查是否 存在安裝好的 MarkupSafe ,如果有,使用 MarkupSafe 的 Markup 類。
所以如果你想加速,只需要導(dǎo)入 MarkupSafe 。
如果沒(méi)有編譯調(diào)試支持模塊并且你在使用一個(gè)沒(méi)有 ctypes 的 Python 安裝( Python 2.4 沒(méi)有 ctypes , Jython 或 Google 的 AppEngine ) Jinja2 不能提供 正確的調(diào)試信息,且回溯可能是不完整的。這也是為什么現(xiàn)在不能與 Jython 或是 AppEngine 良好工作的原因,沒(méi)有 ctypes 就不可能使用調(diào)試支持?jǐn)U展。
如果你在 Google Appengine 開(kāi)發(fā)服務(wù)器上工作,你可以把 ctypes 模塊添加到 白名單來(lái)恢復(fù)回溯。這無(wú)論如何都不能用于生產(chǎn)環(huán)境:
import os
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
from google.appengine.tools.dev_appserver import HardenedModulesHook
HardenedModulesHook._WHITE_LIST_C_MODULES += ['_ctypes', 'gestalt']
這個(gè)片段的聲譽(yù)見(jiàn) Thomas Johansson
Python 2.3 中缺少許多在 Jinja2 中大量使用的特性。做出這個(gè)艱難的決定是因?yàn)槭褂眉?將到來(lái)的 Python 2.6 和 3.0 版本,再為老版本 Python 維護(hù)代碼更加困難。如果你確實(shí) 需要 Python 2.3 支持,你可以使用 [Jinja 1][4] 或其它仍然支持 2.3 的模板引擎。
在某些情況下, Jinja 的作用域會(huì)是任意的:
layout.tmpl:
{% macro foo() %}LAYOUT{% endmacro %}
{% block body %}{% endblock %}
child.tmpl:
{% extends 'layout.tmpl' %}
{% macro foo() %}CHILD{% endmacro %}
{% block body %}{{ foo() }}{% endblock %}
這在 Jinja2 中會(huì)打印 LAYOUT 。這是父模板在子模板之后求值的副作用。 這允許子模板傳遞信息到父模板。要避免這個(gè)問(wèn)題,重命名父模板中的變量或宏 讓它們有不同的前綴。