Qu'est-ce que Jinja ?
Jinja est un moteur de modèles (templates) qui permet de mettre en forme du texte ; sa syntaxe s'inspire de Django et de Python.
Les modèles Jinja sont de simples fichiers texte. Un modèle contient des variables et/ou des expressions, remplacées par des valeurs au moment où le modèle est rendu, ainsi que des balises, qui pilotent la logique du modèle.
Vous trouverez la documentation officielle de Jinja ici
Fonctions de base
Manipulez les entrées à l'aide d'instructions simples (filtres et expressions) pour obtenir le résultat souhaité.
Par exemple : obtenir la liste des prix de tous les produits, arrondis à 2 décimales.
products | map(attribute='item.price') | map('round', 2) | listVous n'avez besoin de connaître que quelques notions simples :
Accès aux attributs
Vous pouvez accéder aux attributs avec un point ou des crochets (pour les variables)
foo = { bar: 'hey' }
foo.bar # => 'hey'
var1 = 'bar'
foo[var1] # => 'hey'Affectations
Les affectations utilisent la balise set et peuvent avoir plusieurs cibles :
{% set prices = products | map(attribute='item.price') | list %}
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = 'my_key', 'my_value' %}Expressions
Elles fonctionnent de façon très proche du Python classique ; même si vous ne travaillez pas avec Python, vous devriez vous y retrouver facilement.
Littéraux
La forme la plus simple d'expression est le littéral. Les littéraux représentent des objets Python, comme des chaînes de caractères et des nombres. Voici les littéraux disponibles :"Hello World"Tout ce qui se trouve entre deux guillemets doubles ou simples est une chaîne de caractères. Les chaînes sont utiles chaque fois que vous en avez besoin dans le modèle (par exemple comme arguments d'appels de fonctions et de filtres, ou simplement pour étendre ou inclure un modèle).42/123_456Les entiers sont des nombres sans partie décimale. Le caractère « _ » peut servir à séparer les groupes de chiffres pour plus de lisibilité.42.23/42.1e2/123_456.789Les nombres à virgule flottante s'écrivent avec un « . » comme séparateur décimal. Ils peuvent aussi s'écrire en notation scientifique, avec un « e » majuscule ou minuscule pour indiquer l'exposant. Le caractère « _ » peut servir à séparer les groupes de chiffres pour plus de lisibilité, mais pas dans l'exposant.['list', 'of', 'objects']Tout ce qui se trouve entre deux crochets est une liste. Les listes servent à stocker des données séquentielles que l'on parcourt ensuite.('tuple', 'of', 'values')Les tuples sont des listes non modifiables (« immuables »). Un tuple qui ne contient qu'un seul élément doit être suivi d'une virgule (('1-tuple',)). Les tuples servent généralement à représenter des ensembles de deux éléments ou plus. Voir l'exemple de liste ci-dessus pour plus de détails.{'dict': 'of', 'key': 'and', 'value': 'pairs'}En Python, un dict est une structure qui associe des clés à des valeurs. Les clés doivent être uniques et ont toujours exactement une valeur.true/falsetrue est toujours vrai et false est toujours faux.Remarque : les constantes spéciales true, false et none s'écrivent bien en minuscules. Comme cela a déjà prêté à confusion (True était autrefois interprété comme une variable non définie, donc considérée comme fausse), les trois peuvent désormais aussi s'écrire avec une majuscule (True, False et None). Par souci de cohérence (tous les identifiants sont en minuscules), utilisez toutefois les versions en minuscules.
Calcul
Permet d'effectuer des calculs sur des valeurs. Les opérateurs suivants sont pris en charge :+Additionne deux objets. En général, il s'agit de nombres, mais si les deux objets sont des chaînes ou des listes, vous pouvez ainsi les concaténer. Ce n'est toutefois pas la méthode recommandée pour concaténer des chaînes ! Pour cela, utilisez plutôt l'opérateur~.{{ 1 + 1 }}vaut2.-Soustrait le second nombre du premier.{{ 3 - 2 }}vaut1./Divise deux nombres. Le résultat est un nombre à virgule flottante.{{ 1 / 2 }}vaut{{ 0.5 }}.//Divise deux nombres et renvoie la partie entière du résultat.{{ 20 // 7 }}vaut2.%Calcule le reste d'une division entière.{{ 11 % 7 }}vaut4.*Multiplie l'opérande de gauche par celui de droite.{{ 2 * 2 }}renvoie4. Permet aussi de répéter une chaîne plusieurs fois :{{ '=' * 80 }}affiche une barre de 80 signes égal.**Élève l'opérande de gauche à la puissance de l'opérande de droite.{{ 2**3 }}renvoie8. Contrairement à Python, les puissances enchaînées sont évaluées de gauche à droite :{{ 3**3**3 }}est évalué comme(3**3)**3, alors que Python l'évaluerait comme3**(3**3). Utilisez des parenthèses pour préciser l'ordre voulu.
Comparaisons
==Vérifie si deux objets sont égaux.!=Vérifie si deux objets sont différents.>vrai si la partie gauche est supérieure à la partie droite.>=vrai si la partie gauche est supérieure ou égale à la partie droite.<vrai si la partie gauche est inférieure à la partie droite.<=vrai si la partie gauche est inférieure ou égale à la partie droite.
Logique
andRenvoie vrai si l'opérande de gauche et celui de droite sont vrais.orRenvoie vrai si l'opérande de gauche ou celui de droite est vrai.notInverse une condition (voir ci-dessous).(expr)Les parenthèses regroupent une expression.Remarque : les opérateurs
isetinacceptent aussi la négation en notation infixe :foo is not baretfoo not in barau lieu denot foo is baretnot foo in bar. Toutes les autres expressions exigent une notation préfixe :not (foo and bar).
Autres opérateurs
Les opérateurs suivants sont très utiles mais n'entrent dans aucune des deux autres catégories :inTeste l'appartenance à une séquence ou à un dictionnaire. Renvoie vrai si l'opérande de gauche est contenu dans celui de droite. Par exemple,1 in [1, 2, 3]renvoie true.isEffectue un test.|(pipe, barre verticale)Applique un filtre.~(tilde)Convertit tous les opérandes en chaînes et les concatène."Hello " ~ name ~ "!"renvoieHello John!(si name == ‘John’)()Appelle un objet appelable :post.render(). Entre les parenthèses, vous pouvez utiliser des arguments positionnels et des arguments nommés, comme en Python :post.render(user, full=true)../[]Récupère un attribut d'un objet. (Voir Variables)
Filtres
Les variables peuvent être modifiées par des filtres. Il s'agit d'une bibliothèque de fonctions utilitaires qui effectuent les transformations à votre place. Les filtres sont séparés de la variable par une barre verticale (|) et peuvent recevoir des arguments facultatifs entre parenthèses. Plusieurs filtres peuvent être enchaînés : le résultat de l'un est transmis au suivant.
Par exemple, name | trim | capitalize supprime les espaces autour du nom et met sa première lettre en majuscule.
Les filtres qui acceptent des arguments les placent entre parenthèses, comme pour un appel de fonction. Par exemple : listx | join(', ') assemble une liste en séparant les éléments par des virgules.
Vous pouvez utiliser un if en ligne avec des filtres : 'multiple' if array | count > 1 else 'one'
Beaucoup de filtres de liste renvoient des itérateurs (pour les boucles) plutôt que des listes : pensez à utiliser le filtre list.
Filtres intégrés
Liste complète des filtres
Filtres intégrés de JinjaFiltres les plus utilisés
5 filtres sont signalés par l'étiquette [must know]. Ce sont les filtres de base à connaître : ils couvrent la plupart des opérations de manipulation de données. Les autres restent utiles, mais vous pourrez les consulter plus tard, le moment venu.default
Valeur par défaut si l'entrée n'existe pasPython'hey' | default('my_variable is not defined') => "hey" None | default('my_variable is not defined') => "my_variable is not defined"capitalize / title / lower / upper
Change la casse d'une chaînePython'hello' | capitalize => "Hello" 'arbitrary code execution' | title => "Arbitary Code Execution" 'this is an example' | upper => "THIS IS AN EXAMPLE" 'THIS IS AN EXAMPLE' | lower => "this is an example"map [must know]
Deux usages principaux :Extraire des attributs des objets d'une liste
Appliquer un filtre à tous les éléments d'une liste
Pythonproducts = [ {name: 'abc', nested: {price: 2.77}}, {name: 'def', nested: {price: 3.82}}, {name: 'ghi', nested: {price: 1.39}} ] products | map(attribute='name') | map('capitalize') | list => ['Abc', 'Ghi', 'Def'] products | map(attribute='nested.price') | map('round', 1) | list => [2.8, 3.8, 1.4]selectattr / rejectattr [must know]
Filtre une liste d'objets selon leurs attributs
Prend en arguments un attribut et un test (voir la section Tests)Pythonusers = [ {name: 'abc', active: True, role: 'admin'}, {name: 'def', active: False, role: 'admin'}, {name: 'ghi', active: True, role: 'builder'} ] users | selectattr('role', '==', 'admin') | list => [ {name: "abc", active: True, role: "admin"}, {name: "def", active: False, role: "admin"} ] users | selectattr('active') | list => [ {name: "abc", active: True, role: "admin"}, {name: "ghi", active: True, role: "builder"} ] # reverse of select users | rejectattr('active') | list => [ {name: "def", active: False} ] # with a regex apps = [ {name: 'bosv1', database: 'bos-pgsql-v1'}, {name: 'boav1', database: 'boa-mango'}, {name: 'bosv2', database: 'bos-pgsql-v2'} ] apps | selectattr('database', 'search', '.*pgsql.*') | list => [ {name: 'bosv1', database: 'bos-pgsql-v1'}, {name: 'bosv2', database: 'bos-pgsql-v2'} ]select / reject [must know]
Prend un test en argument (voir la section Tests)Python# simple selects numbers | select("odd") numbers | select("even") numbers | select("divisibleby", 3) numbers | select("lessthan", 42) # Reject is reversed of select numbers | reject('odd') # Fin the number of users who are admin (assuming a map of roles) ['admin', 'nope', 'admin'] | select("==", "admin") | list => ['admin', 'admin'] | count => 2 # filter undefined variables after a map operation [undefined, "hey", "oh"] | select('defined') | list => ["hey", "oh"] # select items containing "v1" ["prod-v1", "prod_v2", "item_v1"] | select("in", "v1") | list => ["prod-v1", "item_v1"] # with regex ["p-v1_lk", "c-v2", "m-v1-lk"] | select("search", ".*v1(-|_)lk") | list => ["p-v1_lock", "m-v1-lock"]flatten [must know]
Après un map, des select ou des manipulations plus complexes, il est fréquent d'obtenir des listes de ce type : `[[1,2], [3,4]]`
Utilisez flatten pour les fusionner en une seule listePython[[1, 2], [3, 4]] | flatten => [1, 2, 3, 4]list [must know]
Convertit une valeur en liste. Vous l'utiliserez souvent, car la plupart des filtres utiles renvoient des itérateurs et non des listes : il faut alors les reconvertir manuellement en listes.join
Python['abc', 'def', 'ghi'] | join(', ') => "abc, def, ghi" [{name: 'abc'}, {name: 'def'}] | join(', ', attribute='name') => "abc, def"dictsort
Pythonfor key, value in mydict | dictsort => #sort the dict by key, case insensitive for key, value in mydict | dictsort(reverse=true) => #sort the dict by key, case insensitive, reverse order for key, value in mydict | dictsort(true) => #sort the dict by key, case sensitive for key, value in mydict | dictsort(false, 'value') => #sort the dict by value, case insensitiveformat
Met en forme une chaîne (printf)Python"%s, %s!" | format('Hello', 'world') Hello, world!groupby
Pythonusers = [ {name: 'pierre', city: 'paris'}, {name: 'leo', city: 'marseille'}, {name: 'lucy', city: 'paris'} ] # Useful to use with for loops (for city, items in users | groupby('city')) users | groupby("city") => [ ["marseille", [ {"city":"marseille", "name": "leo"} ] ], ["paris", [ {"city": "paris", "name": "pierre"}, {"city": "paris", "name": "lucy"} ] ] ] apps = [ {name: 'bos', database: 'bos-pgsql-staging'}, {name: 'boa', database: 'bos-pgsql-staging'}, {name: 'bos', database: 'bos-pgsql-prod'}, {anon: true, database: 'Anon-mvp-pgsql-other'} ] apps | groupby("name", default: 'unknown') => [ ["bos", [ {name: 'bos', database: 'bos-pgsql-staging'}, {name: 'bos', database: 'bos-pgsql-prod'}, ], ["boa", [ {name: 'boa', database: 'bos-pgsql-staging'} ] ], ["unknown", [ {anon: true, database: 'Anon-mvp-pgsql-other'} ] ] ]int / string
Python'43' | int => 43 'h43' | int => 0 34 | string => '34' {name: 'hello'} | string => "{name: 'hello'}"first / last
Python[1, 2, 3] | first => 1 [1, 2, 3] | last => 3length / count
Python[1, 2, 3] | length => 3 [1, 3, 5, 10] | count # alias => 4max / min
Python[1, 2, 3] | min => 1 [{code: 1}, {code: 2}] | max(attribute='code') => 2random
Python['a', 'b', 'c'] | random => 'c' # random item of the listreplace
Python'Hello World' | replace('Hello', 'Goodbye') => "Goodbye World" # Restrict to the first x occurences 'aaaaargh' | replace('a', 'd,', 2) => d,d,aaarghreverse
Python['a', 'b', 'c'] | reverse | list => ['c', 'b', 'a']round
Python42.55 | round => 43.0 42.55 | round(1, 'floor') => 42.5 42.54 | round(1, 'ceiling') => 42.6slice
Python['a', 'b', 'c'] | slice(3) | list => [['a'], ['b'], ['c']]sort
Python['b', 'a'] | sort | list => ["a", "b"] ['a', 'b'] | sort(reverse=true) | list => ["b", "a"] ['a', 'B', 'A'] | sort(case_sensitive=true) | list => ["A", "B", "a"] [{text: 'b'}, {text: 'a'}] | sort(attribute='text') | list => [{text: 'a'}, {text: 'b'}]sum
Python[22, 48] | sum => 70 [{price: 22}, {price: 48}] | sum(attribute='price') => 70trim
Python" hello " | trim => "hello"truncate
Python"foo bar baz qux" | truncate(9) => "foo..." # Truncate regardless of words "foo bar baz qux" | truncate(9, True) => "foo ba..." # Truncate use a default leeway of 5, the fourth parameter. "foo bar baz qux" | truncate(11) => "foo bar baz qux" "foo bar baz qux" | truncate(11, False, '[...]', 0) => "foo bar[...]"unique
Filtres personnalisés
Ces filtres supplémentaires sont développés par ViaSay.
Filtres de date
Les filtres suivants convertissent des chaînes représentant une date ou une durée en objets Python datetime/timedelta.
to_date : convertit une chaîne en objet datetime ; prend tzname en paramètre.
{% set departure="20230730T1028" | to_date("Europe/Paris") %}
{% set departure=departure.strftime("%H:%M:%S - %d/%m/%Y") %}
# departure will contain the following value: "10:28:00 - 30/07/2023"to_timedelta : convertit une chaîne de durée en objet timedelta.
{% set time_before_departure="1 day, 17:02:31" | to_timedelta %}
{% set today="20230730T1028" | to_date("Europe/Paris") %}
{% set departure=today + time_before_departure %}
{% set departure=departure.strftime("%H:%M:%S - %d/%m/%Y") %}
# departure will contain the following value: "03:30:03 - 01/08/2023"timestamp_to_date : convertit un timestamp Unix (entier en millisecondes) en datetime
{% set departure=1691597204000 | timestamp_to_date %}
{% set departure=departure.strftime("%H:%M:%S - %d/%m/%Y") %}
# departure will contain the following value: "16:06:44 - 09/08/2023"Attention : vous ne pouvez pas stocker un datetime dans une variable de sortie de l'étape Data Manipulation, sous peine d'erreur d'exécution. Vous devez d'abord le convertir en chaîne avec strftime, comme dans les exemples ci-dessus.
Tests
En plus des filtres, des « tests » sont disponibles. Ils permettent de vérifier une variable par rapport à une expression courante. Pour tester une variable ou une expression, ajoutez is suivi du nom du test après la variable. Par exemple, pour savoir si une variable est définie, écrivez name is defined, qui renvoie true ou false selon que name est défini ou non dans le contexte du modèle.
Les tests peuvent aussi accepter des arguments. Si le test ne prend qu'un seul argument, vous pouvez omettre les parenthèses.
Méthodes natives de Python
Vous pouvez utiliser la plupart des méthodes natives des objets Python.
Par exemple, vous pouvez découper une chaîne ou fusionner des dicts :
"abc, def, ghi".split(', ')
=> ['abc', 'def', 'ghi']
{name: 'pierre'}.update({role: 'admin'})
=> {name: 'pierre', role: 'admin'}Voici les méthodes disponibles pour les principaux types d'objets :
Utilisation avancée
Description de toutes les fonctionnalités du moteur de modèles utilisables dans le bloc de code. Elles permettent des manipulations plus avancées avec des boucles, des if multiples, des fonctions, etc. (programmation impérative).
Nous utilisons Jinja 3 pour les modèles. Si vous avez besoin de références ou de précisions après avoir lu ce document, consultez leur documentation officielle.
Jinja étant dérivé de Python, vous retrouverez de nombreuses similitudes et pourrez même utiliser certaines méthodes Python sur certains objets.
Délimiteurs
Il existe plusieurs types de délimiteurs. Les délimiteurs par défaut sont les suivants :
{% ... %}pour les instructions (n'affichent aucune valeur){{ ... }}pour les expressions (affichées dans le résultat du modèle){# ... #}pour les commentaires, non inclus dans le résultat du modèle
Dans le bloc de code, vous pouvez tous les utiliser, mais le résultat affiché est de toute façon ignoré. Vous utiliserez donc surtout les instructions et les commentaires.
Dans les sorties, les valeurs sont encapsulées dans une expression, pour rester simple.
Affectations
Les affectations utilisent la balise set et peuvent avoir plusieurs cibles :
{% **set** navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% **set** key, value = call_something() %}Portée des variables
Gardez à l'esprit qu'une variable définie à l'intérieur d'un bloc (sauf un if, qui ne crée pas de portée) n'est pas visible à l'extérieur de ce bloc. Il en va de même pour les boucles. Par conséquent, le modèle suivant ne fera pas ce que vous attendez :Python{% set iterated = false %} {% for item in seq %} {{ item }} {% set iterated = true %} {% endfor %} {% if not iterated %} did not iterate {% endif %}Ce n'est pas possible. Utilisez plutôt d'autres constructions, comme le bloc else de la boucle ou la variable spéciale loop :
Python{% for item in seq %} {{ item }} {% else %} did not iterate {% endfor %}Les cas plus complexes peuvent être traités avec des objets namespace, qui permettent de propager des modifications d'une portée à l'autre :
Python{% set ns = namespace(found=false) %} {% for item in items %} {% if item.check_something() %} {% set ns.found = true %} {% endif %} * {{ item.title }} {% endfor %} Found item having something: {{ ns.found }}
Liste des structures de contrôle
If / elif / else
L'instruction if est comparable à celle de Python. Dans sa forme la plus simple, elle permet de vérifier qu'une variable est définie, non vide et non fausse :Python{% if users %} {% set text = 'users' %} {% endif %}Pour plusieurs branches, elif et else s'utilisent comme en Python. Vous pouvez aussi y employer des expressions plus complexes :
Python{% if kenny.sick %} {% set text = 'Kenny is sick.' %} {% elif kenny.dead %} {% set text = 'You killed Kenny! You ****!!!' %} {% else %} {% set text = 'Kenny looks okay --- so far' %} {% endif %}If peut aussi s'utiliser comme expression en ligne :
Python{% set text = 'layout' if layout_template is defined else 'default' %}et pour filtrer une boucle :
Python{% for user in users if not user.hidden %} {% do usernames.append(user) %} {% endfor %}For
Parcourt chaque élément d'une séquence. Par exemple :
Python{% for user in users %} {% do array.append(user | trim | capitalize) %} {% endfor %}Comme les variables des modèles conservent les propriétés de leurs objets (issues de Python), il est possible de parcourir des conteneurs comme les dicts :
Python{% for key, value in my_dict.items() %} {% array.append([key, value]) %} {% endfor %}Les dictionnaires Python ne sont pas forcément dans l'ordre où vous souhaitez les afficher. Si l'ordre compte, utilisez le filtre
| dictsort.Python{% for key, value in my_dict | dictsort %} {% array.append([key, value]) %} {% endfor %}À l'intérieur d'un bloc de boucle for, vous avez accès à quelques variables spéciales :
Variable
Description
loop.index
L'itération en cours de la boucle (à partir de 1).
loop.index0
L'itération en cours de la boucle (à partir de 0).
loop.revindex
Le nombre d'itérations restantes jusqu'à la fin de la boucle (à partir de 1)
loop.revindex0
Le nombre d'itérations restantes jusqu'à la fin de la boucle (à partir de 0)
loop.first
Vrai s'il s'agit de la première itération.
loop.last
Vrai s'il s'agit de la dernière itération.
loop.length
Le nombre d'éléments de la séquence.
loop.cycle
Une fonction utilitaire qui alterne entre les valeurs d'une liste.
loop.depth
Indique le niveau de profondeur atteint dans une boucle récursive. Commence à 1
loop.depth0
Indique le niveau de profondeur atteint dans une boucle récursive. Commence à 0
loop.previtem
L'élément de l'itération précédente. Non défini lors de la première itération.
loop.nextitem
L'élément de l'itération suivante. Non défini lors de la dernière itération.
loop.changed(*val)
Vrai si la fonction a été appelée précédemment avec une valeur différente (ou jamais appelée).
Dans une boucle for, il est possible d'alterner entre plusieurs chaînes ou variables à chaque passage grâce à la fonction spéciale loop.cycle :
Python{% for row in rows %} {% set css_class = loop.cycle('odd', 'even') %} {% do array.append([css_class, row]) %} {% endfor %}Contrairement à Python, il est impossible d'utiliser break ou continue dans une boucle. Vous pouvez en revanche filtrer la séquence pendant le parcours, ce qui permet d'ignorer certains éléments. L'exemple suivant ignore tous les utilisateurs masqués :
Python{% for user in users if not user.hidden %} {% do filtered_users.append(user) %} {% endfor %}L'avantage est que la variable spéciale loop compte correctement, sans tenir compte des utilisateurs non parcourus.
Si aucune itération n'a eu lieu, parce que la séquence était vide ou que le filtrage en a retiré tous les éléments, vous pouvez afficher un bloc par défaut avec else :
Python{% for user i users %} {% do array.append(user) %} {% else %} {% do array.append('empty') %} {% endfor %}En Python, les blocs else s'exécutent chaque fois que la boucle correspondante ne s'est pas interrompue par un break. Comme les boucles ne peuvent de toute façon pas être interrompues, le mot-clé else se comporte ici un peu différemment.
Il est aussi possible d'utiliser des boucles récursives, pratique pour traiter des données récursives comme des plans de site ou du RDFa. Pour cela, ajoutez le modificateur recursive à la définition de la boucle, puis appelez la variable loop avec le nouvel itérable là où vous voulez lancer la récursion.
L'exemple suivant construit un plan de site avec des boucles récursives :
Python{% for item in sitemap recursive %} {% set title = item.title %}</a> {% if item.children %} {% do loop(item.children) %} {% endif %} {% do array.append(title) %} {% endfor %}La variable loop désigne toujours la boucle la plus proche (la plus interne). Avec plusieurs niveaux de boucles, vous pouvez réaffecter la variable loop en écrivant {% set outer_loop = loop %} après la boucle à utiliser de façon récursive, puis l'appeler avec {{ outer_loop(…) }}
Notez que les affectations faites dans une boucle sont effacées à la fin de l'itération et ne survivent pas à la portée de la boucle. Consultez Affectations, portée des variables, pour savoir comment gérer ce cas.
Si vous voulez simplement vérifier si une valeur a changé depuis l'itération précédente ou va changer à la suivante, utilisez previtem et nextitem :
Python{% for value in values %} {% if loop.previtem is defined and value > loop.previtem %} The value just increased! {% endif %} {{ value }} {% if loop.nextitem is defined and loop.nextitem > value %} The value will increase even more! {% endif %} {% endfor %}Si seule compte la question de savoir si la valeur a changé, changed est encore plus simple :
Python{% for entry in entries %} {% if loop.changed(entry.category) %} <h2>{{ entry.category }}</h2> {% endif %} <p>{{ entry.message }}</p> {% endfor %}
Liste des fonctions globales
range
Renvoie une liste contenant une progression arithmétique d'entiers.range(i, j)renvoie[i, i+1, i+2, ..., j-1]; le début vaut0par défaut. Si un pas (step) est fourni, il indique l'incrément (ou le décrément). Par exemple,range(4)etrange(0, 4, 1)renvoient[0, 1, 2, 3]. La borne de fin est exclue ! Ce sont exactement les indices valides d'une liste de 4 éléments.
C'est utile pour répéter un bloc du modèle plusieurs fois, par exemple pour remplir une liste. Imaginez que vous avez 7 utilisateurs dans la liste mais que vous souhaitez afficher trois éléments vides pour imposer une hauteur en CSS :Python<ul> {% for user in users %} <li>{{ user.username }}</li> {% endfor %} {% for number in range(10 - users | count) %} <li class="empty"><span>...</span></li> {% endfor %} </ul>lipsum
Génère du texte lorem ipsum pour le modèle. Par défaut, cinq paragraphes HTML de 20 à 100 mots chacun sont générés. Si html vaut False, du texte brut est renvoyé. Pratique pour produire un contenu simple afin de tester une mise en page.dict
Une alternative pratique aux littéraux de dict.{'foo': 'bar'}équivaut àdict(foo='bar').cycler
Parcourt des valeurs en les renvoyant une à une, puis recommence au début une fois la fin atteinte.
Semblable àloop.cycle, mais utilisable en dehors des boucles ou sur plusieurs boucles. Par exemple, pour afficher une liste de dossiers et de fichiers en leur attribuant alternativement les classes « odd » et « even ».
Chaque argument positionnel est renvoyé dans l'ordre indiqué à chaque cycle.propriétés
current
Renvoie l'élément courant, c'est-à-dire celui qui sera renvoyé au prochain appel de[next()](https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-globals.cycler.next).next()
Renvoie l'élément courant, puis fait avancer[current](https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-globals.cycler.current)à l'élément suivant.reset()
Revient au premier élément.
joiner
Un petit utilitaire qui sert à « joindre » plusieurs sections. On passe une chaîne à un joiner, qui la renvoie à chaque appel sauf le premier (où il renvoie une chaîne vide). Vous pouvez l'utiliser ainsi pour assembler des éléments :namespace
Crée un nouveau conteneur qui accepte l'affectation d'attributs avec la balise{% set %}:Python{% set ns = namespace() %} {% set ns.foo = 'bar' %}Son but principal est de pouvoir transmettre une valeur de l'intérieur d'une boucle vers une portée extérieure. Les valeurs initiales peuvent être fournies sous forme de dict, d'arguments nommés, ou des deux (même comportement que le constructeur dict de Python) :
Python{% set ns = namespace(found=false) %} {% for item in items %} {% if item.check_something() %} {% set ns.found = true %} {% endif %} {{ item.title }} {% endfor %} Found item having something: {{ ns.found }}
Macros (fonctions)
Les macros sont comparables aux fonctions des langages de programmation classiques. Elles permettent de regrouper des blocs souvent utilisés dans des fonctions réutilisables, pour ne pas vous répéter (principe « DRY »).
Voici un petit exemple de macro qui affiche un élément de formulaire :
{% set registered_users = [] %}
{% macro register_users(users, bot='', role='basic') -%}
{% for user in users %}
{% do registered_users.append(user.update({role: role, bot: 'a'})) %}
{% endfor %}
{%- endmacro %}
{% macro filter_sensitive(text, filter='[SENSITIVE]') -%}
{# bank cards #}
{% set filtered = text | regex_replace('^4[0-9]{12}(?:[0-9]{3})?$', filter) %}
{# phone numbers #}
{% set filtered = filtered | regex_replace('^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$', filter) %}
{{ filtered }}
{%- endmacro %}La macro peut ensuite être appelée comme une fonction dans le namespace :
register_users([{name: 'pierre'}, {name: 'paul'}], role='admin')
register_users([{name: 'leo'}, {name: 'lucy'}], role='builder', bot='op')
=> registered_users = [
{name: 'pierre', role: 'admin', bot=''},
{name: 'paul', role: 'admin', bot=''},
{name: 'leo', role: 'builder', bot='op'},
{name: 'lucy', role: 'builder', bot='op'}
]Dans une macro, vous avez accès à trois variables spéciales :
varargs
Si la macro reçoit plus d'arguments positionnels qu'elle n'en accepte, ceux-ci sont placés dans la variable spéciale varargs, sous forme de liste de valeurs.kwargs
Comme varargs, mais pour les arguments nommés. Tous les arguments nommés non utilisés sont stockés dans cette variable spéciale.caller
Si la macro a été appelée depuis une balise call, l'appelant est stocké dans cette variable sous forme de macro appelable.
Les macros exposent aussi certains de leurs détails internes. Les attributs suivants sont disponibles sur un objet macro :
name
Le nom de la macro.{{ input.name }}afficheinput.arguments
Un tuple contenant les noms des arguments acceptés par la macro.catch_kwargs
Vrai si la macro accepte des arguments nommés supplémentaires (c'est-à-dire si elle utilise la variable spéciale kwargs).catch_varargs
Vrai si la macro accepte des arguments positionnels supplémentaires (c'est-à-dire si elle utilise la variable spéciale varargs).caller
Vrai si la macro utilise la variable spéciale caller et peut être appelée depuis une balise call.
Une macro dont le nom commence par un tiret bas (underscore) n'est pas exportée et ne peut pas être importée.
Call
Dans certains cas, il peut être utile de passer une macro à une autre macro. Pour cela, utilisez le bloc spécial call.
Il est aussi possible de renvoyer des arguments au bloc call, ce qui en fait une alternative aux boucles. De manière générale, un bloc call fonctionne exactement comme une macro sans nom.