Jinja: Prise en charge des variables imbriquées

Créé le 7 déc. 2016  ·  7Commentaires  ·  Source: pallets/jinja

J'ai recherché dans la documentation et divers articles en ligne et je n'ai trouvé aucune mention d'avoir des variables imbriquées, j'ouvre donc une demande de fonctionnalité. Cela pourrait aider de nombreux projets en permettant des appels de variables plus complexes et automatiques.

Une variable normale peut être définie comme ceci :

{{ variable }}

Il serait utile de permettre aux informations dynamiques d'une autre variable d'être utilisées pour remplir un autre nom de variable.

{{ variable{{ generated_var }} }}

Mon cas d'utilisation exact est avec Ansible. Je récupère une liste de périphériques d'interface réseau à partir d'une variable (ansible_interfaces). Ensuite, je peux l'utiliser pour référencer les informations d'une autre variable (ansible_eth0, par exemple). Voici un cadre de base de ce que l'on essaie d'accomplir.

{% for interface in ansible_interfaces %}
IPADDR{{ loop.index }}={{ ansible_{{ interface }}.ipv4.address }}
NETMASK{{ loop.index }}={{ ansible_{{ interface }}.ipv4.netmask }}
{% endfor %}

Jinja2 n'aime pas ça quand il rend car il se plaint des crochets supplémentaires existants. Pour les options sur la façon de mettre en œuvre cela, je pensais à l'une de ces deux idées différentes.

(1) Autoriser l'expansion variable. C'est exactement ce que je montrais plus tôt; permettant aux variables d'être analysées de l'intérieur vers l'extérieur.

(2) Ajoutez un filtre pour convertir une chaîne en un nom de variable.

{% for interface in ansible_interfaces %}
{% set interface_string="ansible_%s.ipv4.address"|format(interface) %}
IPADDR{{ loop.index }}={{ interface_string|variable }}
NETMASK{{ loop.index }}={{ interface_string|variable }}
{% endfor %}

Voici un code approximatif (non fonctionnel) montrant la deuxième idée.

# vim jinja2/jinja2/filters.py
<strong i="21">@environmentfilter</strong>
def do_variable(environment, s):
    string_to_variable = "{{ %s }}" % s
    return environment.from_string(string_to_variable).render()

Idéalement, l'option 1 serait moins complexe en termes d'utilisation par l'utilisateur final. Faites-moi part de vos réflexions sur la question. C'est la première fois que je me penche sur le code de Jinja2, mais j'aimerais contribuer en retour si une aide est nécessaire avec le code.

Commentaire le plus utile

http://serverfault.com/questions/762079/how-to-loop-through-interface-facts

On dirait que tu peux faire ça :

{{ hostvars[inventory_hostname]['ansible_%s' | format(interface)].ipv4.address }}

Je suis très fort :-1: sur les noms de variables variables. C'est généralement le signe d'une mauvaise architecture si une application ne fournit pas de dict/liste de données appropriée si vous devez y accéder par clé dynamique ou itérer dessus. FWIW, je pense que ce hostvars dict est un peu moche comparé à un dict approprié mappant les noms d'interface aux données d'interface. J'ouvrirais un problème avec Ansible, suggérant de changer cette liste en un dict. Étant donné que l'itération sur un dict vous donne ses clés, il pourrait même ne pas être rétrocompatible s'ils le changeaient en un dict ...

Tous les 7 commentaires

http://serverfault.com/questions/762079/how-to-loop-through-interface-facts

On dirait que tu peux faire ça :

{{ hostvars[inventory_hostname]['ansible_%s' | format(interface)].ipv4.address }}

Je suis très fort :-1: sur les noms de variables variables. C'est généralement le signe d'une mauvaise architecture si une application ne fournit pas de dict/liste de données appropriée si vous devez y accéder par clé dynamique ou itérer dessus. FWIW, je pense que ce hostvars dict est un peu moche comparé à un dict approprié mappant les noms d'interface aux données d'interface. J'ouvrirais un problème avec Ansible, suggérant de changer cette liste en un dict. Étant donné que l'itération sur un dict vous donne ses clés, il pourrait même ne pas être rétrocompatible s'ils le changeaient en un dict ...

Je suis à 100% d'accord pour dire que le rendu à l'envers pour obtenir des noms de variables variables * N est une MAUVAISE idée.

Cependant, je suis arrivé ici à la recherche d'une solution pour l' imbrication de rendu extérieur à l' nested_render serait-il bénéfique ou nuisible dans la mesure où il est susceptible de semer la confusion ?

Les variables imbriquées résoudraient un problème avec WTForms, dans lequel une construction comme
{{ form.playername(value="{{ currentname }}") }}
serait beaucoup plus clair que toute autre solution que j'ai trouvée.

{{ form.playername(value=currentname) }} fait. mais pour info, vous devriez transmettre les données actuelles au constructeur de formulaire et ne pas vous en soucier dans les modèles du tout

Ah, c'est aussi simple que ça ! J'ai fini par utiliser Javascript pour définir la valeur de la variable currentname. Lorsque je définis la valeur par défaut dans l'objet de formulaire dans le code Python, il ne se met pas à jour.

Passez par #pocoo sur IRC et envoyez-moi un ping (c'est très hors sujet ici) et je pourrai vous dire comment le faire correctement.

Cette page vous a été utile?
0 / 5 - 0 notes