J'ai le modèle suivant 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 %}
Si la condition est remplie dans la boucle for
, j'aimerais changer mybool
en true pour pouvoir afficher mybool is true!
ci-dessous. Cependant, il semble que la portée de la variable mybool
intérieure soit limitée à l'instruction if
, de sorte que la valeur souhaitéemybool
n'est jamais définie.
Comment définir la variable "globale" mybool
afin de pouvoir l'utiliser dans la dernière instruction if
?
MODIFIER
J'ai trouvé quelques suggestions (seulement les pages vues en cache correctement), mais elles ne semblent pas fonctionner. Peut-être qu'ils sont obsolètes dans Jinja2 ...
MODIFIER
Solution fournie ci-dessous. Je suis toujours curieux de savoir pourquoi les suggestions ci-dessus ne fonctionnent pas. Est-ce que quelqu'un sait avec certitude qu'ils ont été déconseillés?
Une façon de contourner cette limitation est d'activer l'extension d'instruction d'expression "do" et d'utiliser un tableau au lieu d'un booléen
{% set exists = [] %}
{% for i in range(5) %}
{% if True %}
{% do exists.append(1) %}
{% endif %}
{% endfor %}
{% if exists %}
<!-- exists is true -->
{% endif %}
Pour activer l'extension de déclaration d'expression "do" de Jinja: e = jinja2.Environment(extensions=["jinja2.ext.do",])
Réponse à une question connexe: je voulais avoir un compteur global du nombre de fois où j'ai entré un certain if-block dans le modèle et fini avec le ci-dessous.
En haut du modèle:
{% set counter = ['1'] %}
Dans le bloc if, je veux compter:
{% if counter.append('1') %}{% endif %}
Lors de l'affichage du compte:
{{ counter|length }}
La chaîne '1'
peut être remplacée par n'importe quelle chaîne ou chiffre, je crois. C'est toujours un hack, mais pas très grand.
Vous pouvez résoudre votre problème en utilisant ce hack (sans extensions):
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'}}])
Mise à jour 2018
À partir de Jinja 2.10 (8 nov. 2017), un objet namespace()
permet de résoudre ce problème particulier. Voir le document officiel Assignments documentation pour plus de détails et un exemple; la documentation class
montre ensuite comment affecter plusieurs valeurs à un espace de noms.
Lors de l'écriture de contextfunction()
ou de quelque chose de similaire, vous avez peut-être remarqué que le contexte tente de vous empêcher de le modifier.
Si vous avez réussi à modifier le contexte à l’aide d’une API de contexte interne, vous avez peut-être remarqué que les modifications apportées au contexte ne semblaient pas visibles dans le modèle. La raison en est que Jinja
utilise le contexte uniquement comme source de données principale pour les variables de modèle pour des raisons de performances.
Si vous souhaitez modifier le contexte, écrivez une fonction qui retourne une variable que vous pouvez affecter à une variable en utilisant set:
{% set comments = get_latest_comments() %}
Avait besoin de trouver le nombre maximum d'entrées dans un objet (objet) à partir d'une liste (objects_from_db),
Cela n'a pas fonctionné pour des raisons connues dans jinja2 et à portée variable.
{% set maxlength = 0 %}
{% for object in objects_from_db %}
{% set ilen = object.entries | length %}
{% if maxlength < ilen %}
{% set maxlength = ilen %}
{% endif %}
{% endfor %}
Voici ce qui fonctionne:
{% 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] %}
J'espère que cela aidera quelqu'un d'autre à essayer de comprendre la même chose.
Trouvé cet excellent article qui décrit un petit bidouillage. Il n'est pas possible de changer la valeur d'une variable jinja dans une autre portée, mais il est possible de modifier les valeurs d'un dictionnaire global:
# 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}}
J'ai également trouvé très utile cette syntaxe pour définir la valeur sans utiliser réellement set
:
{%- if foundUser.update({'flag':True}) %}{%- endif %}
En fait, il vérifie le résultat d'une opération update
sur un dictionnaire (note to self).