Может ли переменная Jinja расширяться во внутреннем блоке? - программирование
Подтвердить что ты не робот

Может ли переменная Jinja расширяться во внутреннем блоке?

У меня есть следующий шаблон Jinja:

{% set mybool = False %}
{% for thing in things %}
    <div class='indent1'>
        <ul>
            {% if current_user %}
              {% if current_user.username == thing['created_by']['username'] %}
                {% set mybool = True %}
                <li>mybool: {{ mybool }}</li> <!-- prints True -->
                <li><a href='#'>Edit</a></li>
              {% endif %}
            {% endif %}
            <li>Flag</li>
        </ul>
    </div>
    <hr />
{% endfor %}

{% if not mybool %}
    <!-- always prints this -->
    <p>mybool is false!</p>
{% else %}
  <p>mybool is true!</p>
{% endif %}

Если условие выполнено в цикле for, я хотел бы изменить mybool на true, чтобы я мог отображать mybool is true! ниже. Однако похоже, что объем внутреннего mybool ограничен инструкцией if, поэтому желаемый mybool никогда не устанавливается.

Как я могу установить "global" mybool, чтобы я мог использовать его в последнем выражении if?

ИЗМЕНИТЬ

Я нашел некоторые предложения (правильно просмотрены только кешированные страницы), но они, похоже, не работают. Возможно, они устарели в Jinja2...

ИЗМЕНИТЬ

Решение приведено ниже. Мне все еще интересно, почему вышеприведенные предложения не работают. Кто-нибудь знает наверняка, что они устарели?

4b9b3361

Ответ 1

Один из способов ограничения этого ограничения - включить расширение выражения "do" и использовать массив вместо boolean:

{% set exists = [] %}
{% for i in range(5) %}
      {% if True %}
          {% do exists.append(1) %}
      {% endif %}
{% endfor %}
{% if exists %}
    <!-- exists is true -->
{% endif %}

Чтобы включить расширение выражения выражения Jinja "do": e = jinja2.Environment(extensions=["jinja2.ext.do",])

Ответ 2

Отвечайте на связанный с этим вопрос: я хотел иметь глобальный счетчик числа раз, когда я ввел определенный шаблон if в шаблон, и в итоге получился ниже.

В верхней части шаблона:

{% set counter = ['1'] %}

В if-блоке я хочу подсчитать:

{% if counter.append('1') %}{% endif %}

При отображении счета:

{{ counter|length }}

Строка '1' может быть заменена любой строкой или цифрой, я полагаю. Это все еще хак, но не очень большой.

Ответ 3

Вы можете решить свою проблему, используя этот хак (без расширений):

import jinja2

env = jinja2.Environment()
print env.from_string("""
{% set mybool = [False] %}
{% for thing in things %}
    <div class='indent1'>
        <ul>
            {% if current_user %}
              {% if current_user.username == thing['created_by']['username'] %}
                {% set _ = mybool.append(not mybool.pop()) %}
                <li>mybool: {{ mybool[0] }}</li> <!-- prints True -->
                <li><a href='#'>Edit</a></li>
              {% endif %}
            {% endif %}
            <li>Flag</li>
        </ul>
    </div>
    <hr />
{% endfor %}

{% if not mybool[0] %}
    <!-- always prints this -->
    <p>mybool is false!</p>
{% else %}
  <p>mybool is true!</p>
{% endif %}
""").render(current_user={'username':'me'},things=[{'created_by':{'username':'me'}},{'created_by':{'username':'you'}}])

Ответ 4

Обновление 2018

Начиная с Jinja 2.10 (8 ноября 2017 г.) существует объект namespace() для решения этой конкретной проблемы. См. официальную документацию по назначениям для получения более подробной информации и примера; class документация затем иллюстрирует, как назначить несколько значений пространству имен.

Ответ 5

При написании contextfunction() или что-то подобное вы, возможно, заметили, что контекст пытается остановить вас от его изменения.

Если вам удалось изменить контекст с помощью внутреннего контекстного API, вы, возможно, заметили, что изменения в контексте не выглядят видимыми в шаблоне. Причина этого заключается в том, что Jinja использует контекст только как первичный источник данных для переменных шаблона по причинам производительности.

Если вы хотите изменить контекст, напишите функцию, которая возвращает переменную вместо нее, которую можно назначить переменной с помощью set:

{% set comments = get_latest_comments() %}

Источник

Ответ 6

Требуется найти максимальное количество записей в объекте (объекте) из списка (objects_from_db),

Это не работает по причинам, известным в jinja2 и переменной области.

 {% set maxlength = 0 %}
 {% for object in objects_from_db %}
     {% set ilen = object.entries | length %}
     {% if maxlength < ilen %}
         {% set maxlength = ilen %}
     {% endif %}
 {% endfor %}

Вот что работает:

 {% set mlength = [0]%}
 {% for object in objects_from_db %}
     {% set ilen = object.entries | length %}
     {% if mlength[0] < ilen %}
         {% set _ = mlength.pop() %}
         {% set _ = mlength.append(ilen)%}
     {% endif %}
 {% endfor %}
 {% set maxlength = mlength[0] %}

Надеюсь, это поможет кому-то еще попытаться понять то же самое.

Ответ 7

Нашел эту замечательную статью, которая описывает небольшой взлом. Изменить значение переменной jinja в другой области невозможно, но можно изменить значения глобального словаря:

# works because dictionary pointer cannot change, but entries can 

{% set users = ['alice','bob','eve'] %} 
{% set foundUser = { 'flag': False } %} 

initial-check-on-global-foundUser: 
  cmd.run: 
    name: echo initial foundUser = {{foundUser.flag}} 

{% for user in users %} 
{%- if user == "bob" %} 
{%-   if foundUser.update({'flag':True}) %}{%- endif %} 
{%- endif %} 
echo-for-{{user}}: 
  cmd.run: 
    name: echo my name is {{user}}, has bob been found? {{foundUser.flag}} 
{% endfor %} 

final-check-on-global-foundUser: 
  cmd.run: 
    name: echo final foundUser = {{foundUser.flag}}

Я также нашел очень полезным этот синтаксис для установки значения без фактического использования set:

{%-   if foundUser.update({'flag':True}) %}{%- endif %} 

На самом деле он проверяет результат операции update над словарем (примечание к себе).

Ответ 8

Здесь общий случай для любого, кто хочет использовать объект namespace(), чтобы переменная сохранялась вне цикла for.

{% set accumulator = namespace(total=0) %}
{% for i in range(0,3) %}
    {% set accumulator.total = i + accumulator.total %}
    {{accumulator.total}}
 {% endfor %}'          {# 0 1 3 #}
 {{accumulator.total}}  {# 3 (accumulator.total persisted past the end of the loop) #}