常见问题¶
这一页回答了一些关于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
在金贾。这是父模板在子模板之后求值的副作用。这允许子模板将信息传递给父模板。若要避免此问题,请将父模板中的宏或变量重命名为具有不常见的前缀。