¿Qué es Jinja?
Jinja es un motor de plantillas que permite dar formato al texto; su sintaxis está inspirada en Django y Python.
Las plantillas Jinja son simplemente archivos de texto... Una plantilla contiene variables y/o expresiones, que se reemplazan por valores cuando se renderiza una plantilla; y etiquetas, que controlan la lógica de la plantilla.
Puedes consultar la documentación oficial de Jinja: aquí
Funciones básicas
Manipula las entradas con instrucciones sencillas (filtros y expresiones) para obtener el resultado deseado.
Por ejemplo, obtener la lista de precios de todos los productos y redondearlos a 2 decimales.
products | map(attribute='item.price') | map('round', 2) | listSolo necesitarás conocer algunas cosas sencillas:
Acceso a atributos
Puedes acceder a los atributos con un punto o corchetes (para las variables)
foo = { bar: 'hey' }
foo.bar # => 'hey'
var1 = 'bar'
foo[var1] # => 'hey'Asignaciones
Las asignaciones utilizan la etiqueta set y pueden tener varios destinos:
{% set prices = products | map(attribute='item.price') | list %}
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = 'my_key', 'my_value' %}Expresiones
Funcionan de forma muy similar a Python normal; aunque no trabajes con Python, deberías sentirte cómodo con ellas.
Literales
La forma más sencilla de expresión son los literales. Los literales son representaciones de objetos de Python, como cadenas y números. Existen los siguientes literales:"Hello World"Todo lo que se encuentra entre dos comillas dobles o simples es una cadena. Son útiles cuando necesitas una cadena en la plantilla (por ejemplo, como argumentos de llamadas a funciones y filtros, o simplemente para ampliar o incluir una plantilla).42/123_456Los enteros son números completos sin parte decimal. El carácter «_» puede utilizarse para separar grupos y mejorar la legibilidad.42.23/42.1e2/123_456.789Los números de coma flotante pueden escribirse utilizando «.» como separador decimal. También pueden escribirse en notación científica, con una «e» mayúscula o minúscula para indicar el exponente. El carácter «_» puede utilizarse para separar grupos y mejorar la legibilidad, pero no puede utilizarse en el exponente.['list', 'of', 'objects']Todo lo que se encuentra entre dos corchetes es una lista. Las listas son útiles para almacenar datos secuenciales que se recorrerán.('tuple', 'of', 'values')Las tuplas son como listas que no pueden modificarse («inmutables»). Si una tupla solo tiene un elemento, debe ir seguida de una coma (('1-tuple',)). Las tuplas suelen utilizarse para representar elementos de dos o más componentes. Consulta el ejemplo de la lista anterior para obtener más detalles.{'dict': 'of', 'key': 'and', 'value': 'pairs'}Un diccionario en Python es una estructura que combina claves y valores. Las claves deben ser únicas y siempre tienen exactamente un valor.true/falsetrue siempre es verdadero y false siempre es falso.Nota: Las constantes especiales true, false y none están efectivamente en minúsculas. Como esto causó confusión en el pasado (True se expandía a una variable no definida que se consideraba falsa), ahora las tres también pueden escribirse con mayúscula inicial (True, False y None). Sin embargo, por coherencia (todos los identificadores están en minúsculas), deberías utilizar las versiones en minúsculas.
Matemáticas
Permite realizar cálculos con valores. Se admiten los siguientes operadores:+Suma dos objetos. Normalmente, los objetos son números, pero si ambos son cadenas o listas, puedes concatenarlos de esta manera. Sin embargo, esta no es la forma preferida de concatenar cadenas. Para concatenar cadenas, consulta el operador~.{{ 1 + 1 }}es2.-Resta el segundo número del primero.{{ 3 - 2 }}es1./Divide dos números. El valor devuelto será un número de coma flotante.{{ 1 / 2 }}es{{ 0.5 }}.//Divide dos números y devuelve el resultado entero truncado.{{ 20 // 7 }}es2.%Calcula el resto de una división entera.{{ 11 % 7 }}es4.*Multiplica el operando izquierdo por el derecho.{{ 2 * 2 }}devolvería4. También puede utilizarse para repetir una cadena varias veces.{{ '=' * 80 }}imprimiría una barra de 80 signos de igualdad.**Eleva el operando izquierdo a la potencia del operando derecho.{{ 2**3 }}devolvería8. A diferencia de Python, las potencias encadenadas se evalúan de izquierda a derecha.{{ 3**3**3 }}se evalúa como(3**3)**3, pero en Python se evaluaría como3**(3**3). Utiliza paréntesis para indicar explícitamente el orden deseado.
Comparaciones
==Compara dos objetos para comprobar si son iguales.!=Compara dos objetos para comprobar si son distintos.>verdadero si el lado izquierdo es mayor que el derecho.>=verdadero si el lado izquierdo es mayor o igual que el derecho.<verdadero si el lado izquierdo es menor que el derecho.<=verdadero si el lado izquierdo es menor o igual que el derecho.
Lógica
yDevuelve true si los operandos izquierdo y derecho son true.oDevuelve true si el operando izquierdo o el derecho es true.noNiega una expresión (consulta más abajo).(expr)Los paréntesis agrupan una expresión.Nota: Los operadores
esyintambién admiten la negación mediante notación infija:foo is not baryfoo not in baren lugar denot foo is barynot foo in bar. Todas las demás expresiones requieren notación prefija:not (foo and bar).
Otros operadores
Los siguientes operadores son muy útiles, pero no encajan en ninguna de las otras dos categorías:inRealiza una prueba de pertenencia a una secuencia o asignación. Devuelve true si el operando izquierdo está contenido en el derecho.1 in [1, 2, 3]devolvería true, por ejemplo.esRealiza una prueba.|(barra vertical) Aplica un filtro.~(tilde) Convierte todos los operandos en cadenas y los concatena."Hello " ~ name ~ "!"devolveríaHello John!(si name == ‘John’)()Llama a un objeto invocable:post.render(). Dentro de los paréntesis puedes utilizar argumentos posicionales y argumentos con nombre como en Python:post.render(user, full=true)../[]Obtiene un atributo de un objeto. (Consulta Variables)
Filtros
Las variables pueden modificarse mediante filtros. Son una biblioteca de funciones auxiliares que realizan transformaciones por ti, para que no tengas que hacerlo manualmente. Los filtros se separan de la variable mediante el símbolo de barra vertical (|) y pueden tener argumentos opcionales entre paréntesis. Se pueden encadenar varios filtros. La salida de un filtro se aplica al siguiente.
Por ejemplo, name | trim | capitalize eliminará todos los espacios en blanco de name y lo pondrá en mayúscula inicial.
Los filtros que aceptan argumentos utilizan paréntesis alrededor de estos, igual que una llamada a una función. Por ejemplo: listx | join(', ')“ unirá una lista utilizando comas.
Puedes utilizar If en línea con filtros 'multiple' if array | count > 1 else 'one'
Muchos filtros de listas devuelven iteradores (para bucles) en lugar de listas; asegúrate de utilizar el filtro list.
Filtros integrados
Lista completa de filtros
Filtros integrados de JinjaFiltros utilizados con frecuencia
5 filtros están destacados con la etiqueta [must know]. Estos son los filtros básicos que debes conocer y te ayudarán con la mayoría de las operaciones de manipulación de datos. Los demás también serán útiles, pero puedes consultarlos más adelante cuando los necesites.default
Valor predeterminado si la entrada no existePython'hey' | default('my_variable is not defined') => "hey" None | default('my_variable is not defined') => "my_variable is not defined"capitalize / title / lower / upper
Cambia el uso de mayúsculas y minúsculas de una cadenaPython'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]
Hay dos usos principales:Extraer atributos de objetos de una lista
Aplicar un filtro a todos los elementos de una lista
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]
Filtra una lista de objetos según sus atributos
Acepta como argumento un atributo y una prueba (consulta la sección de pruebas)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]
Acepta una prueba (consulta la sección de pruebas) como argumentoPython# 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]
Después de un map, select o una manipulación de datos más compleja, es habitual terminar con listas como esta: `[[1,2], [3,4]]`
Utiliza flatten para fusionarlas en una sola listaPython[[1, 2], [3, 4]] | flatten => [1, 2, 3, 4]list [must know]
Convierte un valor en una lista. Lo utilizarás a menudo, ya que la mayoría de los filtros útiles devuelven iteradores en lugar de listas y debes convertirlos manualmente de nuevo en listas.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
Da formato a una cadena (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
Filtros personalizados
Estos son filtros adicionales implementados por ViaSay.
Filtros de fecha
Los siguientes filtros permiten convertir cadenas que representan fechas o intervalos en objetos de Python datetime/timedelta.
to_date: Analiza una cadena en un objeto datetime; acepta tzname como parámetro.
{% 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: Analiza una cadena timedelta en un objeto 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: Convierte una marca de tiempo Unix (entero en milisegundos) en un 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"Advertencia: No puedes almacenar un datetime en una variable de salida del paso de manipulación de datos. Esto provocará un error de ejecución. Primero debes convertirlo en una cadena utilizando strftime como se muestra en los ejemplos anteriores.
Pruebas
Además de los filtros, también están disponibles los llamados «tests». Los tests se pueden usar para comprobar una variable con una expresión común. Para comprobar una variable o expresión, se añade es más el nombre del test después de la variable. Por ejemplo, para averiguar si una variable está definida, se puede hacer name is defined, lo que devolverá true o false dependiendo de si name está definida en el contexto de la plantilla actual.
Los tests también pueden aceptar argumentos. Si el test solo acepta un argumento, se pueden omitir los paréntesis.
Métodos nativos de Python
Puedes usar la mayoría de los métodos nativos de los objetos de Python.
Por ejemplo, puedes dividir una cadena o combinar diccionarios:
"abc, def, ghi".split(', ')
=> ['abc', 'def', 'ghi']
{name: 'pierre'}.update({role: 'admin'})
=> {name: 'pierre', role: 'admin'}Estos son los métodos disponibles para los principales tipos de objetos:
Uso avanzado
Descripción de todas las funciones proporcionadas por el motor de plantillas que puedes usar en el bloque de código. Esto te permitirá realizar manipulaciones más avanzadas con bucles, varios if, funciones, etc. (también llamada programación imperativa).
Usamos Jinja 3 para las plantillas. Si necesitas referencias o más detalles después de leer este documento, consulta su documentación oficial.
Está derivado de Python, por lo que verás muchas similitudes e incluso podrás usar algunos métodos de Python en ciertos objetos.
Delimitadores
Hay varios tipos de delimitadores. Los delimitadores predeterminados se configuran de la siguiente manera:
{% ... %}para sentencias (no imprime ningún valor){{ ... }}para expresiones (se imprimen en la salida de la plantilla){# ... #}para comentarios no incluidos en la salida de la plantilla
En el bloque de código puedes usar todos ellos, pero la salida se descartará de todos modos. Por lo tanto, querrás usar sentencias y comentarios.
En las salidas, los valores están envueltos en una expresión para mantener las cosas sencillas.
Asignaciones
Las asignaciones usan la etiqueta set y pueden tener varios destinos:
{% **set** navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% **set** key, value = call_something() %}Comportamiento del ámbito
Ten en cuenta que no es posible establecer variables dentro de un bloque (excepto if, que no introduce un ámbito) y hacer que aparezcan fuera de él. Esto también se aplica a los bucles. Como resultado, la siguiente plantilla no hará lo que podrías esperar:Python{% set iterated = false %} {% for item in seq %} {{ item }} {% set iterated = true %} {% endfor %} {% if not iterated %} did not iterate {% endif %}No es posible hacer esto. En su lugar, usa construcciones alternativas como el bloque else del bucle o la variable especial loop:
Python{% for item in seq %} {{ item }} {% else %} did not iterate {% endfor %}Los casos de uso más complejos se pueden gestionar mediante objetos namespace, que permiten propagar cambios entre ámbitos:
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 }}
Lista de estructuras de control
If / elif / else
La sentencia if es comparable a la sentencia if de Python. En su forma más sencilla, puedes usarla para comprobar si una variable está definida, no está vacía y no es falsa:Python{% if users %} {% set text = 'users' %} {% endif %}Para varias ramas, elif y else se pueden usar como en Python. También puedes usar expresiones más complejas allí:expresiones también:
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 también se puede usar como una expresión en línea:
Python{% set text = 'layout' if layout_template is defined else 'default' %}y para el filtrado de bucles:
Python{% for user in users if not user.hidden %} {% do usernames.append(user) %} {% endfor %}For
Itera sobre cada elemento de una secuencia. Por ejemplo:
Python{% for user in users %} {% do array.append(user | trim | capitalize) %} {% endfor %}Como las variables de las plantillas conservan las propiedades de sus objetos (de Python), es posible iterar sobre contenedores como dict:
Python{% for key, value in my_dict.items() %} {% array.append([key, value]) %} {% endfor %}Es posible que los diccionarios de Python no estén en el orden en que quieres mostrarlos. Si el orden importa, usa el
| dictsortfiltro.Python{% for key, value in my_dict | dictsort %} {% array.append([key, value]) %} {% endfor %}Dentro de un bloque for, puedes acceder a algunas variables especiales:
Variables
Descripción
loop.index
La iteración actual del bucle (indexada desde 1).
loop.index0
La iteración actual del bucle (indexada desde 0).
loop.revindex
El número de iteraciones desde el final del bucle (indexado desde 1).
loop.revindex0
El número de iteraciones desde el final del bucle (indexado desde 0).
loop.first
True si es la primera iteración.
loop.last
True si es la última iteración.
loop.length
El número de elementos de la secuencia.
loop.cycle
Una función auxiliar para alternar entre una lista de secuencias.
loop.depth
Indica la profundidad actual de la representación en un bucle recursivo. Empieza en 1.
loop.depth0
Indica la profundidad actual de la representación en un bucle recursivo. Empieza en 0.
loop.previtem
El elemento de la iteración anterior. No está definido durante la primera iteración.
loop.nextitem
El elemento de la iteración siguiente. No está definido durante la última iteración.
loop.changed(*val)
True si se llamó anteriormente con un valor diferente (o no se llamó en absoluto).
Dentro de un bucle for, es posible alternar entre una lista de cadenas/variables cada vez que se recorre el bucle usando el auxiliar especial loop.cycle:
Python{% for row in rows %} {% set css_class = loop.cycle('odd', 'even') %} {% do array.append([css_class, row]) %} {% endfor %}A diferencia de Python, no es posible usar break o continue en un bucle. Sin embargo, puedes filtrar la secuencia durante la iteración, lo que permite omitir elementos. El siguiente ejemplo omite todos los usuarios ocultos:
Python{% for user in users if not user.hidden %} {% do filtered_users.append(user) %} {% endfor %}La ventaja es que la variable especial loop contará correctamente; por lo tanto, no contará los usuarios sobre los que no se haya iterado.
Si no se realizó ninguna iteración porque la secuencia estaba vacía o el filtrado eliminó todos sus elementos, puedes mostrar un bloque predeterminado usando else:
Python{% for user i users %} {% do array.append(user) %} {% else %} {% do array.append('empty') %} {% endfor %}Ten en cuenta que, en Python, los bloques else se ejecutan siempre que el bucle correspondiente no haya hecho break. Como los bucles no pueden usar break de todos modos, se eligió un comportamiento ligeramente diferente para la palabra clave else.
También es posible usar bucles de forma recursiva. Esto resulta útil si trabajas con datos recursivos, como mapas del sitio o RDFa. Para usar bucles recursivamente, básicamente debes añadir el modificador recursive a la definición del bucle y llamar a la variable loop con el nuevo iterable donde quieras realizar la recursión.
El siguiente ejemplo implementa un mapa del sitio con bucles recursivos:
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 siempre hace referencia al bucle más cercano (el más interno). Si tenemos más de un nivel de bucles, podemos reasignar la variable loop escribiendo {% set outer_loop = loop %} después del bucle que queremos usar recursivamente. Entonces podemos llamarlo usando {{ outer_loop(…) }}
Ten en cuenta que las asignaciones realizadas en los bucles se borrarán al final de la iteración y no pueden sobrevivir al ámbito del bucle. Consulta Asignaciones, comportamiento del ámbito para obtener más información sobre cómo gestionar esto.
Si lo único que quieres hacer es comprobar si algún valor ha cambiado desde la última iteración o cambiará en la siguiente, puedes usar previtem y 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 solo te interesa saber si el valor ha cambiado en algún momento, usar changed es aún más sencillo:
Python{% for entry in entries %} {% if loop.changed(entry.category) %} <h2>{{ entry.category }}</h2> {% endif %} <p>{{ entry.message }}</p> {% endfor %}
Lista de funciones globales
range
Devuelve una lista que contiene una progresión aritmética de enteros.range(i, j)devuelve[i, i+1, i+2, ..., j-1]; el inicio (!) toma0de forma predeterminada. Cuando se proporciona step, especifica el incremento (o decremento). Por ejemplo,range(4)yrange(0, 4, 1)devuelven[0, 1, 2, 3]. ¡El punto final se omite! Estos son exactamente los índices válidos para una lista de 4 elementos.
Esto resulta útil para repetir varias veces un bloque de plantilla, por ejemplo, para rellenar una lista. Imagina que tienes 7 usuarios en la lista, pero quieres representar tres elementos vacíos para imponer una altura con 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
Genera texto lorem ipsum para la plantilla. De forma predeterminada, se generan cinco párrafos de HTML, cada uno de entre 20 y 100 palabras. Si html es False, se devuelve texto normal. Esto resulta útil para generar contenido sencillo para probar el diseño.dict
Una alternativa práctica a los literales de diccionario.{'foo': 'bar'}es lo mismo quedict(foo='bar').cycler
Recorre los valores devolviéndolos uno a uno y vuelve a empezar cuando llega al final.
Similar aloop.cycle, pero se puede usar fuera de los bucles o entre varios bucles. Por ejemplo, representa una lista de carpetas y archivos alternando las clases «odd» y «even».
Cada argumento posicional se devolverá en el orden proporcionado en cada ciclo.propiedades
current
Devuelve el elemento actual. Equivale al elemento que se devolverá la próxima vez que se llame a[next()](https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-globals.cycler.next).next()
Devuelve el elemento actual y luego avanza[current](https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-globals.cycler.current)al elemento siguiente.reset()
Restablece el elemento actual al primero.
joiner
Un pequeño auxiliar que se puede usar para «unir» varias secciones. A un joiner se le pasa una cadena y devolverá esa cadena cada vez que se lo llame, excepto la primera vez (en cuyo caso devuelve una cadena vacía). Puedes usarlo para unir elementos:namespace
Crea un contenedor nuevo que permite asignar atributos mediante la etiqueta{% set %}:Python{% set ns = namespace() %} {% set ns.foo = 'bar' %}El objetivo principal es permitir transportar un valor desde el cuerpo de un bucle hasta un ámbito externo. Se pueden proporcionar valores iniciales como un diccionario, como argumentos con nombre o ambos (el mismo comportamiento que el constructor 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 (funciones)
Las macros son comparables a las funciones de los lenguajes de programación habituales. Son útiles para convertir expresiones idiomáticas de uso frecuente en funciones reutilizables y no repetirse («DRY»).
Este es un pequeño ejemplo de una macro que representa un elemento de formulario:
{% 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 puede entonces llamarse como una función en el espacio de nombres:
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'}
]Dentro de las macros, tienes acceso a tres variables especiales:
varargs
Si se pasan a la macro más argumentos posicionales de los que acepta, terminan en la variable especial varargs como una lista de valores.kwargs
Como varargs, pero para argumentos con nombre. Todos los argumentos con nombre no consumidos se almacenan en esta variable especial.caller
Si la macro se llamó desde una etiqueta call , el llamador se almacena en esta variable como una macro invocable.
Las macros también exponen algunos de sus detalles internos. Los siguientes atributos están disponibles en un objeto macro:
nombre
El nombre de la macro.{{ input.name }}imprimiráinput.arguments
Una tupla con los nombres de los argumentos que acepta la macro.catch_kwargs
Es true si la macro acepta argumentos con nombre adicionales (es decir, si accede a la variable especial kwargs).catch_varargs
Es true si la macro acepta argumentos posicionales adicionales (es decir, si accede a la variable especial varargs).caller
Es true si la macro accede a la variable especial caller y puede llamarse desde una etiqueta call .
Si el nombre de una macro comienza con un guion bajo, no se exporta y no se puede importar.
Call
En algunos casos, puede ser útil pasar una macro a otra macro. Para ello, puedes usar el bloque especial call.
También es posible pasar argumentos de vuelta al bloque call. Esto lo hace útil como sustituto de los bucles. En términos generales, un bloque call funciona exactamente como una macro sin nombre.