Для задания цикла внутри блока?

#python #flask #jinja2

Вопрос:

Вот элементарный цикл, который отлично компилируется за пределами блока назначения:

 {% for item in items %}
  <p>{{item}}</p>
{% endfor %}
 

Но когда я помещаю цикл внутри блока назначения, вот так

 {% set stuff %}
  {% for item in items %}
    <p>{{item}}</p>
  {% endfor %}
{% endset %}
 

Я получаю AssertionError: Tried to resolve a name to a reference that was unknown to the frame ('item') .

Мотивация вопроса заключается в том, что я использую макросы, чтобы избежать дублирования кода. Например, у меня есть несколько разделов с разными полями. Один из дивов содержит сообщение для пользователя. В одном (но только в одном) случае я хотел бы включить a <ul> в этот div, и поэтому я хотел бы просмотреть элементы в списке, обернув каждый из них <li> тегами, прежде чем передавать полученный html в качестве аргумента макросу. Отсюда и мой вопрос.

Можно ли использовать цикл for внутри блока назначения? Или есть лучший способ достичь того же самого?

Комментарии:

1. почему вы им пользуетесь?

2. документация не показывает примеров с for циклом внутри блока назначения-так что, вероятно, его невозможно использовать. И я не знаю, как было бы полезно сгенерировать некоторый HTML — код со значениями, а затем дублировать точно такой же HTML-код, потому что он не будет работать как шаблон, который будет использовать разные items

3. @furas Я использую макросы, чтобы избежать дублирования кода. Например, у меня есть несколько дивов с разными полями. Один из дивов содержит сообщение для пользователя. В одном случае я хотел бы включить a <ul> в этот div, и поэтому я хотел бы просмотреть элементы в списке, обернув каждый из них <li> тегами, прежде чем передавать его в макрос. Отсюда и мой вопрос.

4. @msailor Та информация, которую вы предоставили фурасу в комментарии, действительно важна. Поставьте это в вопрос, чтобы другие, отвечая на ваш вопрос, могли указать альтернативные способы достижения той же цели.

5. Он проверил это напрямую, jinja и я не получаю ваше сообщение об ошибке. Но set у него есть один большой недостаток: он не может получать разные переменные и работает только с items ними . Вы должны вставить for -цикл, macro stuff(items) а затем вы можете использовать stuff(main_items) , stuff(other_items)

Ответ №1:

На основе ошибки утверждения: Пытался разрешить имя ссылки, которая была неизвестна фрейму, эта проблема возникает только в Jinja2 версиях 3.x . Старые версии 2.x работают правильно.

В данный момент ему необходимо задать переменную, прежде чем вы будете использовать ее в блоке. Может быть, позже они это исправят.

 {% set item = None %}

{% set stuff %}
  {% for item in items %}
    <p>{{item}}</p>
  {% endfor %}
{% endset %}

{{ stuff }}
 

Но set у меня есть один большой недостаток: он не может получить аргументы и работает только с items ними .
И это не сработает, если я установлю {% set items = other_items %}

Я бы предпочел ввести код macro для использования stuff(main_items) stuff(other_items) , и т. Д.

 {% macro stuff(items) %}
  {% for item in items %}
    <p>{{item}}</p>
  {% endfor %}
{% endmacro %}

{{ stuff(main_items) }}

{{ stuff(other_items) }}
 

Минимальный рабочий код:

 from flask import Flask, render_template_string

app = Flask(__name__)

@app.route('/')
def index():
    return render_template_string('''
<h1>SET</h1>

{% set item = None %}

{% set stuff_set %}
  {% for item in items %}
    <p>{{item}}</p>
  {% endfor %}
{% endset %}

{{ stuff_set }}

<h1>MACRO</h1>

{% macro stuff_macro(items) %}
  {% for item in items %}
    <p>{{item}}</p>
  {% endfor %}
{% endmacro %}

{{ stuff_macro(main_items) }}
{{ stuff_macro(other_items) }}
''', items=['A', 'B', 'C'], main_items=[1,2,3], other_items=[4,5,6])

if __name__ == '__main__':
    #app.debug = True 
    app.run()
 

Комментарии:

1. Я подам жалобу, так как это похоже на ошибку. Но спасибо за обходной путь!