_كان النموذج الفعلي الذي واجهت فيه المشكلة أولاً هو نموذجي أكثر ، لكن هذا النموذج يصف المشكلة بطريقة أكثر سهولة.
افترض أن لدينا النموذج التالي:
{%- 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 لأن هذا يعمل بشكل جيد أيضًا: