我正在开发一个使用jinja2通过jingo的Django应用程序。我有一个在templates/macros.html
中定义的宏,我需要从helpers.py
中定义的过滤器调用它,因为我必须传递它的参数中涉及某种 python 逻辑。有什么办法吗?
我想要实现的是这样的目标:
在templates/macros.html
:
{% macro render_link(obj) -}
<a href="{{ obj.get_absolute_url() }}">{{ obj }}</a>
-%}
在helpers.py
:
@register.filter
def as_link(obj_or_list):
if hasattr(obj_or_list, '__iter__'):
for obj in obj_or_list:
# call `render_link(obj)` here and concat results somehow
else:
# call `render_link(obj_or_list)` here
每当我需要它时,在我的模板中:
{{ an_object|as_link }}
我需要在这里使用过滤器,因为我需要在将参数传递给宏之前对参数做一些事情。我知道我可以在宏本身中编写逻辑,但我需要在 jinja2 环境中添加一些方法(例如示例中的 hasattr
),当所涉及的逻辑太复杂时,这是不可行的。
经过一番调查,我提出了一个解决方案。宏是在模板中定义的,所以首先我需要加载它。阅读源代码,我发现了如何从模板实例中获取宏函数,因此这是正确的方法:
@register.filter()
def as_link(obj_or_list):
from jingo import env
template = env.get_template('macros.html')
render_link = template.module.render_link
if hasattr(obj_or_list, '__iter__'):
return ''.join((render_link(obj) for obj in obj_or_list))
return render_link(obj_or_list)
我不知道这是否有效,但也许宏已注册为全局函数。宏和全局 Python 函数可以从模板以相同的方式调用。
如果您的宏已注册,您可以:
env.globals['render_link'](obj)
如果这现在有效,则始终可以将宏代码作为 Python 代码包含在筛选器中。在你的过滤器中,你拥有所有的Python功能。