将Python模块导入Jinja模板?

时间:2011-01-28 12:51:31

标签: python jinja2 python-import

是否可以将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'

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

5 个答案:

答案 0 :(得分:52)

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

这样做的方法是将函数注册为jinja2 custom filter,如下所示:

在你的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 %}

答案 1 :(得分:21)

将函数传递给模板,就像这样

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

并在模板中,只需像任何其他函数一样调用它,

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

函数是python中的一等公民,所以你可以像其他任何东西一样传递它们。如果你愿意,你甚至可以传入一个完整的模块。

答案 2 :(得分:6)

模板不知道import,但您可以使用importlib进行教学:

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

(您也可以通过将参数传递给"import"来命名为dict

kwargs = { 'import' : importlib.import_module }
my_template.render( **kwargs )

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

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

答案 3 :(得分:2)

您可以通过将模块__dict__作为参数提供给jinja模板渲染方法来导出模块中的所有可用符号。以下内容将为模板提供__builtin__,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 %}

答案 4 :(得分:1)

您可以像这样将模块传递给 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 -%}