从其它模板引擎切换过来

如果你过去使用过不同的模板引擎,并且想切换到 Jinja,这里是一个小指南,它显示 Python 常见且类似的几个文本模板引擎之间的基本句法和语义变化。

Jinja 1

在 API 使用和模板语法方面,Jinja 2 与 Jinja 1 基本兼容。 以下列表解释 Jinja 1 和 2 之间的差异。

API

Loaders

Jinja 2 使用不同的加载程序 API。 由于模板的内部表示形式已更改,因此不再支持外部缓存系统,如 memcached。 模板消耗的内存现在可与常规 Python 模块相媲美,外部缓存不会带来任何优势。 如果你过去使用过自定义加载程序,请查看新的加载程序 API

从字符串加载模板

过去,可以使用jinja.from_string从具有默认环境配置的字符串生成模板。 Jinja 2 提供了一个Template类,可用于执行相同的操作,但具有可选的附加配置。

unicode 自动转换

Jinja 1 将给定编码的字节串自动转换为 unicode 对象。 这种此转换不再实现,因为它与大多数库都使用常规的 Python ASCII 字节串到 Unicode 的转换不一致。 由 Jinja 2 提供支持的应用程序必须 在任何地方使用 unicode,或者确保仅传递 unicode 字符串给 Jinja 2 。

i18n

Jinja 1 使用自定义翻译程序进行国际化。 i18n 现在可作为Jinja 2扩展程序使用,并使用更简单、更易于获取文本的界面,并支持babel。 有关详细信息,请参阅i18n 扩展

内部方法

Jinja 1 公开了环境对象的一些内部方法,例如call_functionget_attribute 等。 虽然它们被标记为内部方法,但可以重写它们。 Jinja 2 没有等效的方法。

沙盒

Jinja 1 默认运行沙盒模式。 很少有应用程序实际使用该功能,因此在 Jinja 2 中成为可选功能。 有关沙盒执行的更多详细信息,请参阅SandboxedEnvironment

上下文

Jinja 1 具有一个栈式的上下文,用于存储传递到环境的变量。 在 Jinja 2 中,存在一个类似的对象,但是它不允许修改,也不是单例。 由于继承是动态的,因此在模板评估期间可能存在多个上下文对象。

过滤器和测试

筛选器和测试现在是普通功能。 它不再是必要的,并且允许使用工厂函数。

模板

Jinja 2 的语法与 Jinja 1 大致相同。 不同是宏现在需要在参数列表周围括号。

此外,Jinja 2 现在允许动态继承和动态包含。 旧的辅助函数rendertemplate 现在不见了,可以使用include 代替。 不再包含导入宏和变量分配,因为使用了新的import 标签。 Import文档中对此概念进行了说明。

for 标签中发生另一个小变化。 特殊循环变量没有属性,而是必须自己别名循环。 有关详细信息,参见访问父循环

Django

如果你以前使用 Django 模板,你应该会发现 Jinja 非常熟悉。 事实上,大多数语法元素的外观和工作都相同。

但是,Jinja 提供了文档中介绍的更多语法元素,有些工作稍有不同。

本节介绍模板的变化。 由于 API 在根本上很不同,因此我们在这里不做介绍。

方法调用

在Django中,方法调用是隐式工作的,而 Jinja 需要显式的 Python 语法。 因此,下面的 Django 代码:

{% for page in user.get_created_pages %}
    ...
{% endfor %}

…在 Jinja 中看起来像这样:

{% for page in user.get_created_pages() %}
    ...
{% endfor %}

这允许你将变量传递给方法,这在 Django 中是做不到的。 此语法也用于宏。

Filter 的参数

Jinja 为 filters 提供多个参数。 参数传递的语法也不同。 在 Django 中如下所示的模板:

{{ items|join:", " }}

在 Jinja中 看起来像这样:

{{ items|join(', ') }}

它有点冗长,但是它允许使用不同类型的参数(包括变量),并且可以使用多个参数。

测试

除 filters 之外,你还可以使用 is 运算符执行测试。 下面是一些示例:

{% if user.user_id is odd %}
    {{ user.username|e }} is odd
{% else %}
    hmm. {{ user.username|e }} looks pretty normal
{% endif %}

循环

For 循环的工作方式与 Django 非常相似,但值得注意的是,Jinja 循环上下文的特殊变量称为loop,而不是 Django 中的 forloop

此外,在Jinja中,Django 的 empty 参数称为 else 例如,Django 模板:

{% for item in items %}
    {{ item }}
{% empty %}
    No items!
{% endfor %}

… 在 Jinja 中看起来像这样:

{% for item in items %}
    {{ item }}
{% else %}
    No items!
{% endfor %}

Cycle

Jinja 中不存在{% cycle %}标记;但是可以通过对循环上下文特殊变量使用 cycle 方法来实现相同的输出。

以下 Django 模板:

{% for user in users %}
    <li class="{% cycle 'odd' 'even' %}">{{ user }}</li>
{% endfor %}

...看起来像在金贾:

{% for user in users %}
    <li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li>
{% endfor %}

没有等效的 {% 周期 ... 作为 变量 %}.

Mako

如果到目前为止你已经使用过 Mako 并想要切换到 Jinja,则可以将 Jinja 配置为看起来更像Mako:

env = Environment('<%', '%>', '${', '}', '<%doc>', '</%doc>', '%', '##')

通过这样配置的环境,Jinja 应该能够解释 Mako 模板的一小部分。 Jinja 不支持嵌入式 Python 代码,因此你必须将其移出模板。 defs(在 Jinja 中称为宏)和模板继承的语法也不同。 以下 Mako 模板:

<%inherit file="layout.html" />
<%def name="title()">Page Title</%def>
<ul>
% for item in list:
    <li>${item}</li>
% endfor
</ul>

上面的配置在 Jinja 中看起来像这样:

<% extends "layout.html" %>
<% block title %>Page Title<% endblock %>
<% block body %>
<ul>
% for item in list:
    <li>${item}</li>
% endfor
</ul>
<% endblock %>