【问题标题】:In Jinja2, how should an extension add custom filters?在 Jinja2 中,扩展应该如何添加自定义过滤器?
【发布时间】: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 代码中轻松可用。将您的过滤器放在一个模块中,然后提供一个安装函数,将这些过滤器加载到指定为参数的环境中。详情请查看我更新的答案。

标签: python jinja2


【解决方案1】:

是否建议扩展程序向环境添加新的过滤器,而不仅仅是标签和属性?

仅当您需要它们时。否则,为什么要使您的代码过于复杂?过滤器是编写或扩展其他扩展的一个非常常见的用例,作者很可能将其放在那里,因为他们希望这会发生。

这应该在扩展子类的什么地方完成?

它必须在调用时完成,所以如果你不直接把它放在 __init__ 你需要把它放在一个通过 __init__ 调用的辅助方法中强>。

__init__ 中做这样的事情在概念上可以吗?

这很好,只要您的代码的其他用户能够理解它在做什么。最简单的解决方案通常是最好的。

【讨论】:

    猜你喜欢
    • 2011-12-23
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    • 2014-12-01
    相关资源
    最近更新 更多