如何将Python模块导入Jinja模板?

72

我能否将Python模块导入Jinja模板以便使用其中的函数?以format.py文件为例,文件中包含了格式化日期和时间的方法。在Jinja宏中,我可以像下面这样做吗?

{% from 'dates/format.py' import timesince %}

{% macro time(mytime) %}
<a title="{{ mytime }}">{{ timesince(mytime) }}</a>
{% endmacro %}

因为 format.py 不是一个模板,所以上面的代码会给我这个错误:

UndefinedError: the template 'dates/format.py' (imported on line 2 in 'dates/macros.html') does not export the requested name 'timesince'

...但我想知道是否有另一种方法来实现这个目标。

6个回答

69

在模板中,你不能导入Python代码。

要实现此目的,可以将函数注册为jinja2自定义过滤器,例如:

在你的Python文件中:

from dates.format import timesince

environment = jinja2.Environment(whatever)
environment.filters['timesince'] = timesince
# render template here
在你的模板中:
{% macro time(mytime) %}
<a title="{{ mytime }}">{{ mytime|timesince }}</a>
{% endmacro %}

如果您对Jinja过滤器感到困惑,我发现这个链接很有帮助:https://ttl255.com/jinja2-tutorial-part-4-template-filters/ - leftlopez

44

就像这样将函数传递到模板中:

from dates.format import timesince
your_template.render(timesince)

然后在模板中,就像调用其他函数一样调用它即可。

{% macro time(mytime) %}
    <a title="{{ mytime }}">{{ timesince(mytime) }}</a>
{% endmacro %}

在Python中,函数是一等公民,因此您可以像其他任何东西一样传递它们。如果需要,甚至可以传递整个模块。


20

模板不知道 import,但您可以使用importlib来教它:

import importlib
my_template.render( imp0rt = importlib.import_module )  # can't use 'import', because it's reserved

(您也可以通过使用dict参数来将其命名为"import"
kwargs = { 'import' : importlib.import_module }
my_template.render( **kwargs )

然后在jinja模板中,你可以导入任何模块:

{% set time = imp0rt( 'time' ) %}
{{ time.time() }}

4

通过将模块的 __dict__ 作为参数提供给 jinja 模板渲染方法,您可以导出模块中所有可用的符号。以下内容将使内置函数和类型、inspect 和 types 模块的函数和类型在模板中可用。

import __builtin__
import inspect
import types

env=RelEnvironment()
template = env.get_template(templatefile)

export_dict={}
export_dict.update(__builtin__.__dict__)
export_dict.update(types.__dict__)
export_dict.update(inspect.__dict__)

result=template.render(**export_dict)

在模板中,使用类似于以下导出模块的函数:
{%- for element in getmembers(object) -%}
{# Use the getmembers function from inspect module on an object #}
{% endfor %}

2
您可以像这样将模块传递给render函数:
from src.constants import proto

wls = {"workloads": [{"name": "test1", "p": "UDP"}, {"name": "test2", "p": "TCP_NONTLS"}]}

env = Environment(
        loader=PackageLoader("src", "templates")
    )
template = env.get_template("lds.yaml.j2")
print(template.render(wls,proto=proto))

在jinja模板中,您现在可以使用proto
{% if workload.p == proto.udp -%}

0
如果您正在使用Flask,可以使用Flask上下文处理器将导入添加到Jinja上下文中。例如,以下是如何使模块datetimeemail.utilsos.path在所有模板中可用的方法:
app = Flask(__name__)

import email.utils, datetime, os.path
@app.context_processor
def add_imports():
    # Note: we only define the top-level module names!
    return dict(email=email, datetime=datetime, os=os)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接