_我第一次遇到问题的实际模板更像样板,但我以更直观的方式描述了问题。_
假设我们有以下模板:
{%- macro _tag(tag, id=none, classes=(), attrs={}) -%}
<{{ tag }}
{% if id %} id="{{ id }}" {% endif %}
{% if classes %} class="{{ classes|join(' ') }}" {% endif %}
{{ attrs|xmlattr }}>
{% if caller %} {{ caller() }} {% endif %}
</{{ tag }}>
{%- endmacro -%}
以及一个更高级别的模板,该模板会针对某些特定情况尝试{% call %}
:
{%- macro _div() -%}
{% call _tag('div', *varargs, **kwargs) %}
{% autoescape false %}
{% if caller %} {{ caller() }} {% endif %}
{% endautoescape %}
{% endcall %}
{%- endmacro -%}
直观地说,执行{% call _div(...) %} <b>foo</b> {% endcall %}
应该将<b>foo</b>
传递给_tag
宏,然后它会渲染它(逐字逐句,感谢 autoescape)。 但实际结果是UndefinedError: No caller defined
内的{{ caller() }}
行上的_div
。 caller
的范围似乎没有延伸到{% call %}
块中,从而阻止了像上面描述的那样的链式调用。
使用 2.8 中的新块分配功能有一个丑陋的解决方法:
{%- macro _div() -%}
{% set content %}
{% if caller %} {{ caller() }} {% endif %}
{% endset %}
{% call _tag('div', *varargs, **kwargs) %}
{% autoescape false %} {{ content }} {% endautoescape %}
{% endcall %}
{%- endmacro -%}
但是,当然,原始版本会更可取。
我可以用这个小例子重现这个:
{% macro a() %}
start of a
{% call b() %}
{{ caller() }}
{% endcall %}
end of a
{% endmacro %}
{% macro b() %}
start of b
{{ caller() }}
end of b
{% endmacro %}
{% call b() %}
inside b only
{% endcall %}
{#
{% call a() %}
inside a
{% endcall %}
#}
这工作正常,当最后一个块未注释时,我们得到以下回溯:
Traceback (most recent call last):
...
File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 894, in render
return self.environment.handle_exception(exc_info, True)
File "templates/test.j2", line 19, in top-level template code
{% call a() %}
File "templates/test.j2", line 3, in template
{% call b() %}
File "templates/test.j2", line 11, in template
{{ caller() }}
File "templates/test.j2", line 4, in template
{{ caller() }}
jinja2.exceptions.UndefinedError: No caller defined
关于解决方法的小提示:
不需要 2.8 的新功能,因为它也可以正常工作:
{% macro a() %}
start of a
{% set content=caller() %}
{% call b() %}
{{ content }}
{% endcall %}
end of a
{% endmacro %}
{% macro b() %}
start of b
{{ caller() }}
end of b
{% endmacro %}
{% call b() %}
inside b only
{% endcall %}
{% call a() %}
inside a
{% endcall %}
这是有意的,因为它总是作用于最近的宏。 关闭为 wontfix。
仅供参考, {% set caller_ = caller %}
也可以正常工作,然后可以在需要时调用它。
无论如何,这可能值得一个常见问题解答条目。 我记得前段时间一位同事遇到了完全相同的问题,直到我们在进入另一个调用块之前发现{% set caller_ = caller %}
有帮助。
是的,我们可能想把它放到文档中。
最有用的评论
关于解决方法的小提示:
不需要 2.8 的新功能,因为它也可以正常工作: