La scope d’une variable Jinja peut-elle s’étendre au-delà d’un bloc interne?

J’ai le modèle Jinja suivant:

{% set mybool = False %} {% for thing in things %} 
    {% if current_user %} {% if current_user.username == thing['created_by']['username'] %} {% set mybool = True %}
  • mybool: {{ mybool }}
  • Edit
  • {% endif %} {% endif %}
  • Flag

{% endfor %} {% if not mybool %}

mybool is false!

{% else %}

mybool is true!

{% endif %}

Si la condition est remplie dans la boucle for , j’aimerais remplacer mybool par true pour que mybool is true! au dessous de. Cependant, il semble que la scope de mybool interne soit limitée à l’instruction if , de sorte que le mybool souhaité n’est jamais défini.

Comment puis-je définir le mybool “global” pour pouvoir l’utiliser dans la dernière instruction if ?

MODIFIER

J’ai trouvé quelques suggestions (uniquement les pages vues en cache correctement), mais elles ne semblent pas fonctionner. Peut-être qu’ils sont déconseillés à 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éçus?

Un moyen de contourner cette limitation consiste à activer l’ extension “do” expression-expression et à utiliser un tableau au lieu de booléen:

 {% set exists = [] %} {% for i in range(5) %} {% if True %} {% do exists.append(1) %} {% endif %} {% endfor %} {% if exists %}  {% endif %} 

Pour activer l’extension “do” de l’instruction d’expression 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 saisi un certain bloc if dans le modèle, et j’ai abouti à ce qui suit.

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_ssortingng(""" {% set mybool = [False] %} {% for thing in things %} 
    {% if current_user %} {% if current_user.username == thing['created_by']['username'] %} {% set _ = mybool.append(not mybool.pop()) %}
  • mybool: {{ mybool[0] }}
  • Edit
  • {% endif %} {% endif %}
  • Flag

{% endfor %} {% if not mybool[0] %}

mybool is false!

{% else %}

mybool is true!

{% endif %} """).render(current_user={'username':'me'},things=[{'created_by':{'username':'me'}},{'created_by':{'username':'you'}}])

Lors de l’écriture d’une fonction 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 du contexte ne semblent pas être 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 renvoie une variable à la place de celle que vous pouvez affecter à une variable en utilisant set:

{% set comments = get_latest_comments() %}

La source

Besoin de trouver le nombre maximal d’entrées dans un object (object) à partir d’une liste (objects_from_db),

Cela n’a pas fonctionné pour des raisons connues dans jinja2 et la scope variable.

  {% set maxlength = 0 %} {% for object in objects_from_db %} {% set ilen = object.ensortinges | 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.ensortinges | length %} {% if mlength[0] < ilen %} {% set _ = mlength.pop() %} {% set _ = mlength.append(ilen)%} {% endif %} {% endfor %} {% set maxlength = mlength[0] %} 

J'espère que cela aide quelqu'un d'autre à essayer de comprendre la même chose.

Mise à jour 2018

À partir de Jinja 2.10 (8 novembre 2017), il existe un object namespace() pour résoudre ce problème particulier. Voir la documentation officielle des missions pour plus de détails et un exemple; la documentation de la class illustre ensuite comment affecter plusieurs valeurs à un espace de noms.

Trouvé ce grand article qui décrit un petit hack. Il n’est pas possible de changer la valeur d’une variable jinja dans une scope différente, mais il est possible de modifier les valeurs d’un dictionnaire global:

 # works because dictionary pointer cannot change, but ensortinges 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 %} 

Il vérifie en fait le résultat d’une opération de update sur un dictionnaire (note to self).