_私が最初に問題に遭遇した実際のテンプレートは、より定型的なものでしたが、これはより直感的な方法で問題を説明しています。_
次のテンプレートがあるとします。
{%- 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
マクロに渡され、マクロがレンダリングされます(自動エスケープのおかげで逐語的に)。 ただし、実際の結果は、$ _div
内の$ {{ caller() }}
行の$#$ UndefinedError: No caller defined
$#$です。 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 %}
も正常に機能するため、必要なときにいつでも呼び出すことができます。
とにかく、これはFAQエントリの価値があるかもしれません。 別のコールブロックに入る前に{% set caller_ = caller %}
が役立つことがわかるまで、同僚がまったく同じ問題を抱えていたのを覚えています。
ええ、それをドキュメントに入れたいと思うかもしれません。
最も参考になるコメント
回避策についての小さなメモ:
2.8の新機能は、これも正常に機能しているため、必要ありません。