如果你過(guò)去使用一個(gè)不同的模板引擎,并且想要轉(zhuǎn)換到 Jinja2 ,這里是一份簡(jiǎn)小的 指導(dǎo)展示了一些常見(jiàn)的、相似的 Python 文本模板引擎基本語(yǔ)法和語(yǔ)義差異。
Jinja2 與 Jinja1 在 API 使用和模板語(yǔ)法上最為兼容。下面的列表解釋了 Jinja1 和 Jinja2 的區(qū)別。
: Jinja2 使用不同的加載器 API 。因?yàn)槟0宓膬?nèi)部表示更改,不再支持 memcached 這樣的外部緩存系統(tǒng)。模板的內(nèi)存開(kāi)銷與常規(guī)的 Python 模塊相當(dāng),外部緩存不能 帶來(lái)優(yōu)勢(shì)。如果你以前使用了一個(gè)自定義的加載器,請(qǐng)閱讀 loader API部分。
從字符串加載模板
在過(guò)去,在默認(rèn)環(huán)境配置中使用 jinja.from_string 從字符串生成模板是可能 的。 Jinja2 提供了一個(gè) Template 類來(lái)用于做同樣的事情,但是需要 可選的額外配置。
Jinja1 執(zhí)行把字節(jié)串從一個(gè)給定編碼到 unicode 對(duì)象的自動(dòng)轉(zhuǎn)換。這個(gè)轉(zhuǎn)換不再 被實(shí)現(xiàn),因?yàn)樗c大多數(shù)使用常規(guī) Python ASCII 字節(jié)串到 Unicode 轉(zhuǎn)換的庫(kù)不 一致。一個(gè)由 Jinja2 驅(qū)動(dòng)的應(yīng)用 必須 在內(nèi)部的每個(gè)地方都使用 unicode 或 確保 Jinja2 只會(huì)被傳遞 unicode 字符串。
Jinja1 使用自定義的國(guó)際化翻譯器。 i18n 現(xiàn)在作為 Jinja2 的一個(gè)擴(kuò)展,并且 使用更簡(jiǎn)單、更 gettext 友好的接口,并且支持 babel 。更多細(xì)節(jié)見(jiàn) [i18n 擴(kuò)展][2] 。
Jinja1 在環(huán)境對(duì)象上暴露了諸如 call_function 、 get_attribute 等內(nèi)部 方法。當(dāng)它們被標(biāo)記為一個(gè)內(nèi)部方法,則可以覆蓋它們。 Jinja2 并沒(méi)有等價(jià)的 方法。
Jinja1 默認(rèn)運(yùn)行沙箱模式。實(shí)際上只有少數(shù)應(yīng)用使用這一特性,所以這在 Jinja2 中是可選的。更多關(guān)于上下執(zhí)行的細(xì)節(jié)見(jiàn) SandboxedEnvironment 。
Jinja1 有一個(gè)上下文棧存儲(chǔ)傳遞到環(huán)境的變量。在 Jinja2 中有一個(gè)類似的 對(duì)象,但它不允許修改也不是單例的。由于繼承是動(dòng)態(tài)的,現(xiàn)在當(dāng)模板求值時(shí) 可能存在多個(gè)上下文對(duì)象。
過(guò)濾器和測(cè)試現(xiàn)在是常規(guī)的函數(shù)。不再允許使用工廠函數(shù),且也沒(méi)有必要。
Jinja2 與 Jinja1 的語(yǔ)法幾乎相同。區(qū)別是,現(xiàn)在宏需要用小括號(hào)包裹參數(shù)。
此外, Jinja2 允許動(dòng)態(tài)繼承和動(dòng)態(tài)包含。老的輔助函數(shù) rendertemplate 作古, 而使用 include 。包含不再導(dǎo)入宏和變量聲明,因?yàn)椴捎昧诵碌?import 標(biāo)簽。 這個(gè)概念在 導(dǎo)入 文檔中做了解釋。
另一個(gè)改變發(fā)生在 for 標(biāo)簽里。特殊的循環(huán)變量不再擁有 parent 屬性,而 你需要自己給循環(huán)起別名。見(jiàn) 訪問(wèn)父級(jí)循環(huán)了解更多細(xì)節(jié)。
如果你之前使用 Django 模板,你應(yīng)該會(huì)發(fā)現(xiàn)跟 Jinja2 非常相似。實(shí)際上, 很多的語(yǔ)法元素看起來(lái)相同,工作也相同。
盡管如此, Jinja2 提供了更多的在之前文檔中描述的語(yǔ)法元素,并且某些 工作會(huì)有一點(diǎn)不一樣。
本節(jié)介紹了模板差異。由于 API 是從根本上不同,我們不會(huì)再這里贅述。
在 Django 中,方法調(diào)用是隱式的。在 Jinja2 中,你必須指定你要調(diào)用一個(gè)對(duì)象。如 此,這段 Django 代碼:
{% for page in user.get_created_pages %}
...
{% endfor %}
在 Jinja 中應(yīng)該是這樣:
{% for page in user.get_created_pages() %}
...
{% endfor %}
這允許你給函數(shù)傳遞變量,且宏也使用這種方式,而這在 Django 中是不可能的。
在 Django 中你可以使用下面的結(jié)構(gòu)來(lái)判斷是否相等:
{% ifequal foo "bar" %}
...
{% else %}
...
{% endifequal %}
在 Jinja2 中你可以像通常一樣使用 if 語(yǔ)句和操作符來(lái)做比較:
{% if foo == 'bar' %}
...
{% else %}
...
{% endif %}
你也可以在模板中使用多個(gè) elif 分支:
{% if something %}
...
{% elif otherthing %}
...
{% elif foothing %}
...
{% else %}
...
{% endif %}
Jinja2 為過(guò)濾器提供不止一個(gè)參數(shù)。參數(shù)傳遞的語(yǔ)法也是不同的。一個(gè)這樣的 Django 模板:
{{ items|join:", " }}
在 Jinja2 中是這樣:
{{ items|join(', ') }}
實(shí)際上這有點(diǎn)冗贅,但它允許不同類型的參數(shù)——包括變量——且不僅是一種。
除過(guò)濾器外,同樣有用 is 操作符運(yùn)行的測(cè)試。這里是一些例子:
{% if user.user_id is odd %}
{{ user.username|e }} is odd
{% else %}
hmm. {{ user.username|e }} looks pretty normal
{% endif %}
因?yàn)檠h(huán)與 Django 中的十分相似,僅有的不兼容是 Jinja2 中循環(huán)上下文的特殊變 量名為 loop 而不是 Django 中的 forloop 。
Jinja 中沒(méi)有 {% cycle %} 標(biāo)簽,因?yàn)樗请[式的性質(zhì)。而你可以用循環(huán)對(duì)象 的 cycle 方法實(shí)現(xiàn)幾乎相同的東西。
下面的 Django 模板:
{% for user in users %}
<li class="{% cycle 'odd' 'even' %}">{{ user }}</li>
{% endfor %}
Jinja 中看起來(lái)是這樣:
{% for user in users %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li>
{% endfor %}
沒(méi)有與 {% cycle ... as variable %} 等價(jià)的。
如果你迄今使用 Mako 并且想要轉(zhuǎn)換到 Jinja2 ,你可以把 Jinja2 配置成 Mako 一 樣:
env = Environment('<%', '%>', '${', '}', '%')
環(huán)境配置成這樣后, Jinja2 應(yīng)該可以解釋一個(gè) Mako 模板的小型子集。 Jinja2 不支持 嵌入 Python 代碼,所以你可能需要把它們移出模板。 def 的語(yǔ)法(在 Jinja2 中 def 被叫做宏)并且模板繼承也是不同的。下面的 Mako 模板:
<%inherit file="layout.html" />
<%def name="title()">Page Title</%def>
<ul>
% for item in list:
<li>${item}</li>
% endfor
</ul>
在以上配置的 Jinja2 中看起來(lái)是這樣:
<% extends "layout.html" %>
<% block title %>Page Title<% endblock %>
<% block body %>
<ul>
% for item in list:
<li>${item}</li>
% endfor
</ul>
<% endblock %>