在Jinja2中,扩展如何添加自定义过滤器?
我正在研究 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
这里有几个问题:
- 扩展是否应该添加新的过滤器,而不仅仅是标签和属性到环境中?(文档建议这应该是常见做法)
- 在扩展子类中应该在哪里做这个?在 __init__ 中可以获取到环境的引用,所以原则上可以把上面的代码放在 __init__ 方法里。
- 在 __init__ 中做这样的事情在概念上可以吗?我个人不喜欢在其他对象的构造函数中改变对象的状态,但在 Jinja2 中似乎这样做是很自然的,足以成为一个官方扩展(我指的是在 InternationalizationExtension.__init__ 中改变 Environment.globals 和调用 Environment.extend)。
编辑
有一种模式可以至少将过滤器很好地打包成一个 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
1 个回答
0
扩展程序是否应该添加新的过滤器,而不仅仅是标签和属性?
只有在你需要这些过滤器的时候才这样做。否则,为什么要让你的代码变得复杂呢?过滤器是编写或扩展其他扩展程序时非常常见的用法,作者很可能是因为预期会有这样的需求才把它放进去的。
在扩展的子类中应该在哪里做这个?
这个操作必须在调用时进行,所以如果你不直接在__init__里放它,你需要在一个通过__init__调用的辅助方法中放置它。
在__init__中这样做概念上可以吗?
这样做是完全可以的,只要使用你代码的其他人能理解它在做什么。通常,最简单的解决方案是最好的。