Может ли область действия переменной Jinja выходить за пределы внутреннего блока? - PullRequest
54 голосов
/ 02 февраля 2011

У меня есть следующий шаблон 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 никогда не устанавливается.

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

EDIT

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

EDIT

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

Ответы [ 7 ]

46 голосов
/ 03 февраля 2011

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

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

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

14 голосов
/ 06 марта 2014

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

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

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

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

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

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

{{ counter|length }}

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

8 голосов
/ 18 февраля 2014

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

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'}}])
7 голосов
/ 13 мая 2018

Обновление 2018

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

4 голосов
/ 05 октября 2011

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

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

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

{% set comments = get_latest_comments() %}

Источник

3 голосов
/ 19 марта 2017

Требовалось найти максимальное количество записей в объекте (объекте) из списка (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] %}

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

0 голосов
/ 29 августа 2018

Нашел эту замечательную статью , которая описывает небольшой взлом. Невозможно изменить значение переменной 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 со словарем (примечание к себе).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...