2011-02-02 9 views
46

Mam następujący Jinja szablonu:Czy zakres zmiennej Jinja może wykraczać poza wewnętrzny blok?

{% 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 %} 

Jeśli warunek jest spełniony w pętli for chciałbym zmienić mybool true więc mogę wyświetlić mybool is true! poniżej. Wygląda jednak na to, że zakres wewnętrznego modelu mybool jest ograniczony do instrukcji if, dlatego nigdy nie jest ustawiony.

Jak ustawić "globalny" mybool, aby móc go używać w ostatnim oświadczeniu if?

EDIT

Znalazłem some suggestions (tylko buforowane odsłon poprawnie), ale nie wydaje się do pracy. Być może są one przestarzałe w Jinja2 ...

EDIT

Rozwiązanie przedstawione poniżej. Wciąż jestem ciekawy, dlaczego powyższe sugestie nie działają. Czy ktoś wie na pewno, że zostały wycofane?

+1

To nie jest odpowiedź na to pytanie, ale można po prostu ustawić 'mybool' jako zmienna kontekstowego i przekazać je do szablonu – Cameron

+0

to dobre myślenie, ale niestety to nie działa. Jak tylko użyjesz "set" w szablonie, zasięg tej zmiennej jest lokalny. –

+2

> Rozwiązanie dostarczone poniżej. Wciąż jestem ciekawy, dlaczego powyższe sugestie nie działają. Czy ktoś wie na pewno, że zostały wycofane? Zostały one usunięte, ponieważ nie jest możliwe w wygenerowanym kodzie, aby poprawnie przewidzieć, jak daleko będą musiały spłynąć na stosie Pythona. Byłoby to możliwe przy niektórych hakach, ale nie jest to warte wysiłku. Trzymaj logikę z szablonów :) –

Odpowiedz

43

Jednym ze sposobów obejścia tego ograniczenia jest umożliwienie "do" expression-statement extension i używać tablicy zamiast boolean:

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

Aby włączyć Jinja na „nie” rozszerzenie wyrażenie-oświadczenie: e = jinja2.Environment(extensions=["jinja2.ext.do",])

+18

Nie trzeba tego wyrażenia "do" wyrażenia. Umieść wyrażenie w warunku if :) '{% if exists.append (1)%} {% endif%}' – schettino72

+0

Potrzebowałem właściwie zmodyfikować zmienne globalne i skończyło z tablicą: {% set platform = [] %} do odczytu "globalną" zmiennej: {% platformy [1]%} do "zmiana" „globalna zmienna: {% jeśli platform.append (new_platform)%} {% endif%} –

+9

@ schettino72 Jest jeszcze krótszy sposób, aby to zrobić, gdy nie masz wyrażenia "wykonaj": '{% set _ = exists.append (1)%}'. Jest to powszechna praktyka w [DebOps] (http://debops.org/) projekt (materiały do ​​korespondencji) – ypid

3

pisząc contextfunction() lub coś podobnego można zauważyć, że kontekst próbuje powstrzymać cię przed modyfikacją.

Jeśli udało się zmodyfikować kontekst za pomocą wewnętrznego interfejsu API kontekstowego, być może zauważyłeś, że zmiany w kontekście nie są widoczne w szablonie. Powodem tego jest fakt, że Jinja używa kontekstu tylko jako podstawowego źródła danych dla zmiennych szablonu ze względu na wydajność.

Jeśli chcesz zmodyfikować kontekstu napisać funkcję, która zwraca zmienną zamiast które można przypisać do zmiennej za pomocą zestawu:

{% set comments = get_latest_comments() %}

Source

8

można rozwiązać problemu, korzystając ten hack (bez rozszerzeń):

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'}}]) 
13

Odpowiedź na powiązane pytanie: Chciałem mieć globalny licznik liczby wejść do pewnego bloku if w szablonie, a zakończyłem z poniższym.

Na górze szablonu:

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

W razie bloku Chcę policzyć:

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

Podczas wyświetlania Count:

{{ counter|length }} 

Ciąg '1' Moim zdaniem można go zastąpić dowolnym ciągiem lub cyfrą. To wciąż hack, ale nie bardzo duży.

+0

Po prostu odpowiednia ilość hackowania. – mkey

3

Miał potrzebę znalezienia Num max wpisów w obiekt (object) z listy (objects_from_db)

to nie działa ze względów znanych jinja2 i zmiennym zakresie.

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

Oto, co działa:

{% 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] %} 

Nadzieja pomaga to ktoś inny próbuje dowiedzieć się tego samego.

Powiązane problemy