Jinja: {%call%}内で{{caller()}}を使用すると失敗します

作成日 2014年09月23日  ·  5コメント  ·  ソース: pallets/jinja

_私が最初に問題に遭遇した実際のテンプレートは、より定型的なものでしたが、これはより直感的な方法で問題を説明しています。_

次のテンプレートがあるとします。

{%- 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 -%}

しかし、もちろん、元のバージョンの方がはるかに望ましいでしょう。

最も参考になるコメント

回避策についての小さなメモ:

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 %}

全てのコメント5件

私はこの小さな例でこれを再現することができます:

{% 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 %}が役立つことがわかるまで、同僚がまったく同じ問題を抱えていたのを覚えています。

ええ、それをドキュメントに入れたいと思うかもしれません。

このページは役に立ちましたか?
0 / 5 - 0 評価