常见问题

这一页回答了一些关于Jinja的常见问题。

为什么叫Jinja?

之所以选择Jinja这个名字,是因为它是一个日本寺庙的名字,而且这个寺庙和模板有着相似的发音。它不是以乌干达的城市命名的。

它有多快?

我们真的很讨厌基准测试,尤其是因为它们不能反映太多。模板的性能取决于许多因素,您必须在不同的情况下对不同的引擎进行基准测试。测试套件的基准测试表明,Jinja的性能与 Mako 它比Django的模板引擎或Genshi快10到20倍。这些数字应该以吨盐作为基准,这些数字只测试一些与性能相关的情况,如循环。一般来说,模板引擎的性能并不重要,因为Web应用程序中通常的瓶颈是数据库或应用程序代码。

Jinja和Django的兼容性如何?

Jinja的默认语法在许多方面与Django语法匹配。然而,这种相似性并不意味着您可以在Jinja中使用未经修改的Django模板。例如,筛选器参数使用函数调用语法而不是冒号来分隔筛选器名称和参数。此外,Jinja中的扩展接口与Django接口有根本不同,这意味着你的自定义标记将不再工作。

一般来说,您将使用更少的自定义扩展,因为Jinja模板系统允许您使用可以替换大多数Django扩展的特定Python表达式子集。例如,不要使用这样的东西:

{% load comments %}
{% get_latest_comments 10 as latest_comments %}
{% for comment in latest_comments %}
    ...
{% endfor %}

您很可能会提供一个具有属性的对象来从数据库中检索注释:

{% for comment in models.comments.latest(10) %}
    ...
{% endfor %}

或者直接提供模型进行快速测试:

{% for comment in Comment.objects.order_by('-pub_date')[:10] %}
    ...
{% endfor %}

请记住,即使您可以将这些内容放入模板中,但这仍然不是一个好主意。查询应该进入视图代码而不是模板!

把逻辑放入模板不是一个可怕的想法吗?

毫无疑问,您应该尽量从模板中删除尽可能多的逻辑。但是没有任何逻辑的模板意味着你必须在代码中做所有的处理,这是无聊和愚蠢的。一个模板引擎,它与python一起提供并调用 string.Template . 它没有循环和if条件,是迄今为止为python所能获得的最快的模板引擎。

所以在模板中需要一定数量的逻辑来保持每个人的快乐。而Jinja留给你的是你想在模板中加入多少逻辑。你能做什么和不能做什么都有一些限制。

Jinja既不允许将任意Python代码放入模板中,也不允许所有Python表达式。运算符仅限于最常见的运算符,不支持更高级的表达式,如列表理解和生成器表达式。这使模板引擎更易于维护,模板更具可读性。

为什么自动转义不是默认的?

Markup 字符串)与安全和不安全的字符串安全交互。

但是,对于显式转义,模板引擎不必对变量执行任何安全检查。此外,人类知道不转义整数或字符串,这些整数或字符串可能永远不包含必须转义的字符或已经包含HTML标记的字符。例如,当为统计表对整数和浮点表的列表进行迭代时,模板设计器可以省略转义,因为他知道整数或浮点不包含任何不安全的参数。

此外,Jinja是一个通用的模板引擎,不仅用于HTML/XML生成。例如,您可以生成LaTeX、电子邮件、CSS、JavaScript或配置文件。

为什么上下文是不变的?

编写 contextfunction() 时或者类似的事情,你可能已经注意到,上下文试图阻止你修改它。如果您已经使用内部上下文API成功地修改了上下文,那么您可能已经注意到上下文中的更改在模板中似乎不可见。原因是,出于性能原因,Jinja仅将上下文用作模板变量的主数据源。

如果要修改上下文,请编写一个函数,该函数返回一个变量,而不是一个可以使用set:分配给变量的函数:

{% set comments = get_latest_comments() %}

我的回溯看起来很奇怪。怎么回事?

Jinja可以重写回溯,以便它们显示模板行号和源代码,而不是底层的编译代码,但这需要特殊的Python支持。CPython<3.7要求 ctypes ,而PyPy需要透明的代理支持。

如果你使用的是谷歌应用引擎, ctypes 不可用。您可以在开发中使用它,但不能在生产中使用。

import os
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
    from google.appengine.tools.devappserver2.python import sandbox
    sandbox._WHITE_LIST_C_MODULES += ['_ctypes', 'gestalt']

这段代码的优点在于 Thomas Johansson

我的宏被某些内容覆盖

在某些情况下,Jinja范围界定似乎是任意的:

layout.tmpl

{% macro foo() %}LAYOUT{% endmacro %}
{% block body %}{% endblock %}

child.tmpl:

{% extends 'layout.tmpl' %}
{% macro foo() %}CHILD{% endmacro %}
{% block body %}{{ foo() }}{% endblock %}

这将打印 LAYOUT 在金贾。这是父模板在子模板之后求值的副作用。这允许子模板将信息传递给父模板。若要避免此问题,请将父模板中的宏或变量重命名为具有不常见的前缀。