Jinja: El uso de {{ caller() }} dentro de {% call %} falla

Creado en 23 sept. 2014  ·  5Comentarios  ·  Fuente: pallets/jinja

_La plantilla real donde encontré el problema primero era más repetitiva, pero esta describe el problema de una manera más intuitiva._

Supongamos que tenemos la siguiente plantilla:

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

junto con una plantilla de nivel superior que intenta {% call %} para algún caso específico:

{%- macro _div() -%}
  {% call _tag('div', *varargs, **kwargs) %}
    {% autoescape false %}
      {% if caller %} {{ caller() }} {% endif %}
    {% endautoescape %}
  {% endcall %}
{%- endmacro -%}

Intuitivamente, hacer {% call _div(...) %} <b>foo</b> {% endcall %} debería pasar <b>foo</b> a la macro _tag , que luego la renderizaría (palabra literal, gracias al escape automático). Pero el resultado real es UndefinedError: No caller defined en la línea {{ caller() }} dentro de _div . Parecería que el alcance de caller no se extiende al bloque {% call %} , lo que evita llamadas encadenadas como la que se muestra arriba.

Hay una solución fea que utiliza la nueva función de asignación de bloques de 2.8:

{%- macro _div() -%}
  {% set content %}
    {% if caller %} {{ caller() }} {% endif %}
  {% endset %}
  {% call _tag('div', *varargs, **kwargs) %}
    {% autoescape false %} {{ content }} {% endautoescape %}
  {% endcall %}
{%- endmacro -%}

pero, por supuesto, la versión original sería mucho más preferible.

Comentario más útil

Pequeña nota sobre la solución alternativa:

La nueva función de 2.8 no es necesaria ya que también funciona bien:

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

Todos 5 comentarios

Puedo reproducir esto con este pequeño ejemplo:

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

Esto funciona bien tal como está, cuando el último bloque no está comentado, obtenemos el siguiente rastreo:

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

Pequeña nota sobre la solución alternativa:

La nueva función de 2.8 no es necesaria ya que también funciona bien:

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

Esto es algo intencional ya que siempre se enfoca a la macro más cercana. Cerrando como wontfix.

FYI, {% set caller_ = caller %} también funciona bien, luego se puede llamar cuando sea necesario.

De todos modos, esto podría valer la pena una entrada de preguntas frecuentes. Recuerdo que un colega tuvo exactamente el mismo problema hace algún tiempo hasta que descubrimos que {% set caller_ = caller %} antes de pasar a otro bloque de llamadas ayuda.

Sí, es posible que queramos poner eso en los documentos.

¿Fue útil esta página
0 / 5 - 0 calificaciones