【发布时间】:2014-08-27 10:12:15
【问题描述】:
我正在研究Jinja2提供的jinja2.ext.InternationalizationExtension的代码。
我知道可以通过 tags 属性添加标签;当其中一个字符串是 {% %} 块中的第一个标记时,Jinja2 模板解析器将放弃控制并调用用户代码。
class InternationalizationExtension(Extension):
"""This extension adds gettext support to Jinja2."""
tags = set(['trans'])
我从代码中了解到,一个扩展可以通过调用Environment.extend来给环境添加属性;对于 jinja2.ext.InternationalizationExtension,这是在 __init__ 方法中完成的:
def __init__(self, environment):
Extension.__init__(self, environment)
environment.globals['_'] = _gettext_alias
environment.extend(
install_gettext_translations=self._install,
install_null_translations=self._install_null,
install_gettext_callables=self._install_callables,
uninstall_gettext_translations=self._uninstall,
extract_translations=self._extract,
newstyle_gettext=False
)
我知道自定义过滤器是通过向Environment.filters注册函数来添加的:
def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
return value.strftime(format)
environment.filters['datetimeformat'] = datetimeformat
问题是:
- 是否建议扩展添加新的过滤器,而不仅仅是标签和属性到环境? (documentation 建议这应该是常见的做法)
- 这应该在扩展子类的什么地方完成?在 __init__ 中可以使用对环境的引用,因此原则上可以将上述代码放在 __init__ 方法中。
- 在 __init__ 中做这样的事情在概念上是否可行?我个人不喜欢从其他对象的构造函数中更改对象状态,但在 Jinja2 中似乎足以使其成为官方扩展(我说的是更改 Environment.globals 并调用 Environment.extend 来自 InternationalizationExtension.__init__)。
编辑
至少将过滤器很好地封装到 Python 模块中的模式。然而,这个install 函数不能在模板内调用(例如,通过使用扩展创建的自定义CallBlock),因为在模板实例化后不应编辑环境。
def greet(value):
return "Hello %s!" % value
def curse(value):
return "Curse you, %s!" % value
def ohno(value):
return "Oh, No! %s!" % value
def install(env):
env.filters['greet'] = greet
env.filters['curse'] = curse
env.filters['ohno'] = ohno
【问题讨论】:
-
您找到合适的解决方案了吗?我希望在单独的文件/包中提供 Jinja 过滤器,并且我希望使它们易于使用,如果可能的话,可以通过
import my_custom_filters之类的方式使用。 -
如果你想要的是类似于 Django 的 {% load %} 语句的东西,它提供了一种在运行时从模板中加载自定义模板标签和过滤器的统一方法,那么,最好我知道这在 Jinja 中是不可行的,因为环境必须包含过滤器在模板被实例化之前。在我最初的问题中,我还强调 Jinja 似乎并没有真正将自定义过滤器视为扩展的一流成员,并且没有提供一个框架/指南来用一个单一的指令加载一堆它们(甚至从内部Python 代码)。
-
最好的办法是让它们至少从 Python 代码中轻松可用。将您的过滤器放在一个模块中,然后提供一个安装函数,将这些过滤器加载到指定为参数的环境中。详情请查看我更新的答案。