【问题标题】:Custom filter in jinja2 using in bottle在瓶中使用 jinja2 中的自定义过滤器
【发布时间】:2021-10-24 20:21:42
【问题描述】:

我尝试使用 bottle(不是烧瓶)在 jinja2 中定义自定义过滤器。假设我想定义一个pandoc 自定义过滤器。关于jinja2 documentation,我必须这样定义:

from bottle import jinja2_view as view, jinja2_template as template
from jinja2 import environment, filters

def pandoc_convert(s):
    return pypandoc.convert_text(s, format='md', to='html5')

@get("/foo")
def foo():
    return template('foo.html')

environment = jinja2.Environment()
# Putting my custom filter.
environment.filters['pandoc'] = pandoc_convert
run(host='localhost', port=8080, debug=True)

在模板foo.html我有

  {{ "This is *some* markdown" | pandoc }}

当我运行瓶子代码时,它得到了我:

jinja2.exceptions.TemplateAssertionError: No filter named 'pandoc'

但如果您打印environment.filters,那么'pandoc': <function pandoc_convert at 0x7f827e233040>} 会出现在该打印中。

【问题讨论】:

    标签: python jinja2 bottle


    【解决方案1】:

    更新

    这个答案提供了使用 Jinja 的通用说明,但是 看起来bottle 有自己特殊的做事方式。你 需要忽略关于环境和过滤器的 Jinja 文档, 而是钻研瓶源;具体来说, Jinja2Template,看起来像这样:

    class Jinja2Template(BaseTemplate):
        def prepare(self, filters=None, tests=None, globals={}, **kwargs):
            from jinja2 import Environment, FunctionLoader
            self.env = Environment(loader=FunctionLoader(self.loader), **kwargs)
            if filters: self.env.filters.update(filters)
            ...
    

    请注意,prepare 方法接受 filters 关键字参数,用于在其创建的环境中设置过滤器。

    jinja2_template 函数,其定义如下:

    jinja2_template = functools.partial(template, template_adapter=Jinja2Template)
    

    最后,template 函数,它包括:

        if tplid not in TEMPLATES or DEBUG:
            settings = kwargs.pop('template_settings', {})
            if isinstance(tpl, adapter):
                TEMPLATES[tplid] = tpl
                if settings: TEMPLATES[tplid].prepare(**settings)
            elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:
                TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings)
            else:
                TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)
    

    所以,当您致电 jinja2_template("foo.html")(这就是您 做),这变成:

    template("foo.html", template_adapter=Jinja2Template)
    

    template 函数中,模板将调用prepare Jinja2Template 的方法,带有来自 settings 的关键字参数, 它来自template_settingstemplate 的参数。所以, 我们可以使用这样的自定义过滤器:

    import bottle
    
    
    def hellofilter(value):
        return value.replace("hello", "goodbye")
    
    
    @bottle.get("/foo")
    def foo():
        settings = {
            "filters": {
                "hello": hellofilter,
            }
        }
        return bottle.jinja2_template("foo.html", template_settings=settings)
    
    
    if __name__ == "__main__":
        bottle.run(host="127.0.0.1", port=7070, debug=True)
    

    如果我的模板foo.html 看起来像这样:

    This is a test. {{ "hello world"|hello }}
    

    请求127.0.0.1:7070/foo 将返回:

    This is a test. goodbye world
    

    如果我们不想每次都传递 template_settings 参数 我们打电话给jinja2_template,我们可以自己使用functools.partialjinja2_template 函数创建一个包装器:

    import bottle
    import functools
    
    
    def hellofilter(value):
        return value.replace("hello", "goodbye")
    
    
    template_settings = {
        "filters": {
            "hello": hellofilter,
        },
    }
    template = functools.partial(
        bottle.jinja2_template, template_settings=template_settings
    )
    
    
    @bottle.get("/foo")
    def foo():
        return template("foo.html")
    
    
    if __name__ == "__main__":
        bottle.run(host="127.0.0.1", port=7070, debug=True)
    

    【讨论】:

    • 谢谢,但是使用参数它不起作用:你如何转换return template('foo.html', entries=mylist)? “你已经为你的环境定义了一个合适的加载器”是什么意思?
    • 查看我的更新,它提供了特定于 bottle 的说明。
    • 非常感谢您的工作。这通常有效,但在我的 真实 情况下,我收到错误 'Post' object has no attribute 'encode' 与 Post is a class from frontmatter
    • 最好的方法可能是打开一个新问题,并包含重现您所询问的错误的代码。
    猜你喜欢
    • 2020-07-19
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 2014-10-16
    • 1970-01-01
    • 2021-02-24
    • 2012-01-10
    • 1970-01-01
    相关资源
    最近更新 更多