67

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

...但我想知道是否还有其他方法可以实现这一目标。

4

6 回答 6

67

在模板中,不,您不能导入 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 %}
于 2011-01-28T14:04:02.513 回答
39

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

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

在模板中,就像调用任何其他函数一样,

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

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

于 2012-08-08T02:43:00.277 回答
15

模板不知道import,但您可以使用以下方法教授它importlib

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

(您也可以"import"通过使用 a 传递参数来命名它dict

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

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

{% set time = imp0rt( 'time' ) %}
{{ time.time() }}
于 2018-01-15T20:27:12.180 回答
4

您可以通过将模块 __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 %}
于 2013-06-13T08:03:36.057 回答
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 -%}
于 2021-05-11T07:56:18.150 回答
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)
于 2021-08-24T11:01:02.570 回答