Jinja: فشل استخدام {{caller ()}} خلال {٪ call٪}

تم إنشاؤها على ٢٣ سبتمبر ٢٠١٤  ·  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 ، والذي سيعرضه بعد ذلك (حرفيًا ، بفضل 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 -%}

ولكن ، بالطبع ، سيكون الإصدار الأصلي أفضل بكثير.

التعليق الأكثر فائدة

ملاحظة صغيرة حول الحل البديل:

ليست هناك حاجة إلى الميزة الجديدة 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 %} يعمل أيضًا بشكل جيد ، ثم يمكن استدعاؤه عند الحاجة.

على أي حال ، قد يكون هذا يستحق إدخال الأسئلة الشائعة. أتذكر أن أحد الزملاء لديه نفس المشكلة بالضبط منذ بعض الوقت حتى اكتشفنا أن {% set caller_ = caller %} قبل الانتقال إلى حظر اتصال آخر يساعد.

نعم ، قد نرغب في وضع ذلك في المستندات.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات