O que é Jinja?
Jinja é um mecanismo de templates que permite formatar texto; sua sintaxe é inspirada no Django e no Python.
Os templates Jinja são simplesmente arquivos de texto... Um template contém variáveis e/ou expressões, que são substituídas por valores quando o template é renderizado; e tags, que controlam a lógica do template.
Você pode consultar a documentação oficial do Jinja: aqui
Funções básicas
Manipule entradas com instruções simples (filtros e expressões) para obter o resultado desejado.
Por exemplo, obtenha a lista de preços de todos os produtos e arredonde para 2 casas decimais.
products | map(attribute='item.price') | map('round', 2) | listVocê só precisa conhecer algumas coisas:
Acesso a atributos
Você pode acessar atributos com um ponto ou colchetes (para variáveis)
foo = { bar: 'hey' }
foo.bar # => 'hey'
var1 = 'bar'
foo[var1] # => 'hey'Atribuições
As atribuições usam a tag set e podem ter vários destinos:
{% set prices = products | map(attribute='item.price') | list %}
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = 'my_key', 'my_value' %}Expressões
Elas funcionam de forma muito semelhante ao Python comum; mesmo que você não trabalhe com Python, deve sentir-se à vontade com isso.
Literais
A forma mais simples de expressões são os literais. Literais são representações de objetos Python, como strings e números. Existem os seguintes literais:"Hello World"Tudo entre duas aspas duplas ou simples é uma string. Elas são úteis sempre que você precisar de uma string no template (por exemplo, como argumentos de chamadas de funções e filtros, ou apenas para estender ou incluir um template).42/123_456Inteiros são números inteiros sem parte decimal. O caractere ‘_’ pode ser usado para separar grupos e facilitar a leitura.42.23/42.1e2/123_456.789Números de ponto flutuante podem ser escritos usando ‘.’ como separador decimal. Também podem ser escritos em notação científica, com ‘e’ maiúsculo ou minúsculo para indicar o expoente. O caractere ‘_’ pode separar grupos para facilitar a leitura, mas não pode ser usado na parte do expoente.['list', 'of', 'objects']Tudo entre dois colchetes é uma lista. Listas são úteis para armazenar dados sequenciais a serem iterados.('tuple', 'of', 'values')Tuplas são como listas que não podem ser modificadas (“imutáveis”). Se uma tupla tiver apenas um item, ela deverá ser seguida por uma vírgula (('1-tuple',)). Tuplas geralmente são usadas para representar itens com dois ou mais elementos. Consulte o exemplo de lista acima para obter mais detalhes.{'dict': 'of', 'key': 'and', 'value': 'pairs'}Um dict em Python é uma estrutura que combina chaves e valores. As chaves devem ser únicas e sempre ter exatamente um valor.true/falsetrue é sempre verdadeiro e false é sempre falso.Observação: as constantes especiais true, false e none são realmente escritas em minúsculas. Como isso já causou confusão no passado (True era expandido para uma variável indefinida considerada falsa), agora as três também podem ser escritas em maiúsculas (True, False e None). No entanto, por consistência (todos os identificadores são escritos em minúsculas), você deve usar as versões minúsculas.
Matemática
Permite calcular com valores. Os seguintes operadores são compatíveis:+Adiciona dois objetos. Normalmente, os objetos são números, mas, se ambos forem strings ou listas, você poderá concatená-los dessa forma. No entanto, essa não é a forma preferida de concatenar strings! Para concatenação de strings, consulte o operador~.{{ 1 + 1 }}é2.-Subtrai o segundo número do primeiro.{{ 3 - 2 }}é1./Divide dois números. O valor retornado será um número de ponto flutuante.{{ 1 / 2 }}é{{ 0.5 }}.//Divide dois números e retorna o resultado inteiro truncado.{{ 20 // 7 }}é2.%Calcula o resto de uma divisão inteira.{{ 11 % 7 }}é4.*Multiplica o operando esquerdo pelo direito.{{ 2 * 2 }}retornaria4. Isso também pode ser usado para repetir uma string várias vezes.{{ '=' * 80 }}imprimiria uma barra com 80 sinais de igualdade.**Eleva o operando esquerdo à potência do operando direito.{{ 2**3 }}retornaria8. Ao contrário do Python, potências encadeadas são avaliadas da esquerda para a direita.{{ 3**3**3 }}é avaliado como(3**3)**3, mas seria avaliado como3**(3**3)no Python. Use parênteses para deixar explícita a ordem desejada.
Comparações
==Compara dois objetos quanto à igualdade.!=Compara dois objetos quanto à desigualdade.>verdadeiro se o lado esquerdo for maior que o lado direito.>=verdadeiro se o lado esquerdo for maior ou igual ao lado direito.<verdadeiro se o lado esquerdo for menor que o lado direito.<=verdadeiro se o lado esquerdo for menor ou igual ao lado direito.
Lógica
eRetorna true se o operando esquerdo e o direito forem true.ouRetorna true se o operando esquerdo ou o direito for true.nãonega uma instrução (veja abaixo).(expr)Os parênteses agrupam uma expressão.Observação: os operadores
éeintambém permitem negação usando uma notação infixa:foo is not barefoo not in barem vez denot foo is barenot foo in bar. Todas as outras expressões exigem uma notação prefixa:not (foo and bar).
Outros operadores
Os seguintes operadores são muito úteis, mas não se encaixam em nenhuma das outras duas categorias:inExecuta um teste de contenção de sequência/mapeamento. Retorna true se o operando esquerdo estiver contido no direito.1 in [1, 2, 3]retornaria true, por exemplo.éExecuta um teste.|(barra vertical) Aplica um filtro.~(til) Converte todos os operandos em strings e concatena-os."Hello " ~ name ~ "!"retornariaHello John!(se name == ‘John’)()Chama um objeto chamável:post.render(). Dentro dos parênteses, você pode usar argumentos posicionais e nomeados, como no Python:post.render(user, full=true)../[]Obtém um atributo de um objeto. (Consulte Variáveis)
Filtros
As variáveis podem ser modificadas por filtros. Eles são uma biblioteca de funções auxiliares que realizam transformações para você, para que não precise fazê-lo manualmente. Os filtros são separados da variável por um símbolo de barra vertical (|) e podem ter argumentos opcionais entre parênteses. Vários filtros podem ser encadeados. A saída de um filtro é aplicada ao seguinte.
Por exemplo, name | trim | capitalize removerá todos os espaços em branco de name e colocará sua primeira letra em maiúscula.
Filtros que aceitam argumentos têm os argumentos entre parênteses, assim como uma chamada de função. Por exemplo: listx | join(', ') unirá uma lista usando vírgulas.
Você pode usar If inline com filtros 'multiple' if array | count > 1 else 'one'
Muitos filtros de listas retornam iteradores (para loops) em vez de listas; certifique-se de usar o list filtro.
Filtros integrados
Lista completa de filtros
Filtros integrados do JinjaFiltros usados com frequência
5 filtros são destacados com a tag [must know]. Estes são os filtros básicos que você precisa conhecer e ajudarão na maioria das operações de manipulação de dados. Os demais também serão úteis, mas você poderá consultá-los quando precisar.default
Valor padrão se a entrada não existirPython'hey' | default('my_variable is not defined') => "hey" None | default('my_variable is not defined') => "my_variable is not defined"capitalize / title / lower / upper
Altera a capitalização de uma stringPython'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]
Há dois usos principais:Extrair atributos de objetos em uma lista
Aplicar filtro a todos os itens de uma 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 uma lista de objetos com base nos atributos
Recebe um atributo e um teste (consulte a seção de testes) como argumentoPythonusers = [ {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]
Recebe um teste (consulte a seção de testes) 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]
Após um map, select ou uma manipulação de dados mais complexa, é comum terminar com listas como esta: `[[1,2], [3,4]]`
Use flatten para mesclá-las em uma única listaPython[[1, 2], [3, 4]] | flatten => [1, 2, 3, 4]list [must know]
Converte um valor em uma lista. Você o usará com frequência, pois a maioria dos filtros úteis retorna iteradores em vez de listas, e é preciso convertê-los manualmente novamente em 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
Formata uma string (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
Estes são filtros adicionais implementados pela ViaSay.
Filtros de data
Os filtros a seguir permitem converter strings que representam data/intervalo em objetos Python datetime/timedelta.
to_date: Analisa uma string em um objeto datetime; recebe 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: Analisa uma string de timedelta em um 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: Converte um timestamp Unix (inteiro em milissegundos) em um 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"Aviso: Você não pode armazenar um datetime em uma variável de saída da etapa de manipulação de dados. Isso resultará em um erro de execução. Primeiro, é necessário formatá-lo como string usando strftime como mostrado nos exemplos acima.
Testes
Além dos filtros, também estão disponíveis os chamados “testes”. Os testes podem ser usados para testar uma variável em relação a uma expressão comum. Para testar uma variável ou expressão, adicione é mais o nome do teste depois da variável. Por exemplo, para descobrir se uma variável está definida, você pode fazer name is defined, que retornará true ou false dependendo de se name está definida no contexto do modelo atual.
Os testes também podem aceitar argumentos. Se o teste aceitar apenas um argumento, você pode omitir os parênteses.
Métodos nativos do Python
Você pode usar a maioria dos métodos nativos dos objetos Python.
Por exemplo, você pode dividir uma string ou mesclar dicionários:
"abc, def, ghi".split(', ')
=> ['abc', 'def', 'ghi']
{name: 'pierre'}.update({role: 'admin'})
=> {name: 'pierre', role: 'admin'}Aqui estão os métodos disponíveis para os principais tipos de objetos:
Utilização avançada
Descrição de todos os recursos fornecidos pelo mecanismo de modelos que você pode usar no bloco de código. Isso permitirá fazer manipulações mais avançadas com loops, vários ifs, funções etc. (também conhecido como programação imperativa).
Usamos Jinja 3 para os modelos. Se precisar de referências ou de mais detalhes depois de ler este documento, consulte a documentação oficial.
Ele é derivado do Python, portanto você verá muitas semelhanças e poderá até usar alguns métodos do Python em determinados objetos.
Delimitadores
Existem alguns tipos de delimitadores. Os delimitadores padrão são configurados da seguinte forma:
{% ... %}para Instruções (não imprime nenhum valor){{ ... }}para Expressões (imprime na saída do modelo){# ... #}para Comentários não incluídos na saída do modelo
No bloco de código, você pode usar todos eles, mas a saída será descartada de qualquer forma. Portanto, você deverá usar instruções e comentários.
Nas saídas, os valores são envolvidos em uma expressão para manter as coisas simples.
Atribuições
As atribuições usam a tag set e podem ter vários destinos:
{% **set** navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% **set** key, value = call_something() %}Comportamento de escopo
Tenha em mente que não é possível definir variáveis dentro de um bloco (exceto if, que não introduz um escopo) e fazê-las aparecer fora dele. Isso também se aplica a loops. Como resultado, o modelo a seguir não fará o que você talvez espere:Python{% set iterated = false %} {% for item in seq %} {{ item }} {% set iterated = true %} {% endfor %} {% if not iterated %} did not iterate {% endif %}Não é possível fazer isso. Em vez disso, use construções alternativas, como o bloco else do loop ou a variável especial loop:
Python{% for item in seq %} {{ item }} {% else %} did not iterate {% endfor %}Casos de uso mais complexos podem ser tratados usando objetos namespace, que permitem propagar alterações entre escopos:
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 estruturas de controle
If / elif / else
A instrução if é comparável à instrução if do Python. Na forma mais simples, você pode usá-la para testar se uma variável está definida, não está vazia e não é falsa:Python{% if users %} {% set text = 'users' %} {% endif %}Para várias ramificações, elif e else podem ser usados como no Python. Você também pode usar Expressões mais complexas:
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 também pode ser usado como uma expressão inline:
Python{% set text = 'layout' if layout_template is defined else 'default' %}e para filtragem de loops:
Python{% for user in users if not user.hidden %} {% do usernames.append(user) %} {% endfor %}For
Percorre cada item de uma sequência. Por exemplo:
Python{% for user in users %} {% do array.append(user | trim | capitalize) %} {% endfor %}Como as variáveis nos modelos mantêm suas propriedades de objeto (do Python), é possível iterar sobre contêineres como dict:
Python{% for key, value in my_dict.items() %} {% array.append([key, value]) %} {% endfor %}Os dicionários do Python podem não estar na ordem em que você deseja exibi-los. Se a ordem for importante, use o filtro
| dictsort.Python{% for key, value in my_dict | dictsort %} {% array.append([key, value]) %} {% endfor %}Dentro de um bloco for-loop, você pode acessar algumas variáveis especiais:
Variáveis
Descrição
loop.index
A iteração atual do loop. (indexada a partir de 1)
loop.index0
A iteração atual do loop. (indexada a partir de 0)
loop.revindex
O número de iterações desde o final do loop (indexado a partir de 1)
loop.revindex0
O número de iterações desde o final do loop (indexado a partir de 0)
loop.first
Verdadeiro se for a primeira iteração.
loop.last
Verdadeiro se for a última iteração.
loop.length
O número de itens na sequência.
loop.cycle
Uma função auxiliar para alternar entre uma lista de sequências.
loop.depth
Indica a profundidade atual da renderização em um loop recursivo. Começa em 1
loop.depth0
Indica a profundidade atual da renderização em um loop recursivo. Começa em 0
loop.previtem
O item da iteração anterior. Indefinido durante a primeira iteração.
loop.nextitem
O item da iteração seguinte. Indefinido durante a última iteração.
loop.changed(*val)
Verdadeiro se tiver sido chamado anteriormente com um valor diferente (ou se não tiver sido chamado).
Dentro de um for-loop, é possível alternar entre uma lista de strings/variáveis a cada passagem pelo loop usando o auxiliar especial loop.cycle:
Python{% for row in rows %} {% set css_class = loop.cycle('odd', 'even') %} {% do array.append([css_class, row]) %} {% endfor %}Ao contrário do Python, não é possível usar break ou continue em um loop. No entanto, você pode filtrar a sequência durante a iteração, o que permite ignorar itens. O exemplo a seguir ignora todos os usuários ocultos:
Python{% for user in users if not user.hidden %} {% do filtered_users.append(user) %} {% endfor %}A vantagem é que a variável especial loop fará a contagem corretamente; portanto, não contará os usuários sobre os quais não se iterou.
Se nenhuma iteração ocorrer porque a sequência está vazia ou porque a filtragem removeu todos os itens da sequência, você pode renderizar um bloco padrão usando else:
Python{% for user i users %} {% do array.append(user) %} {% else %} {% do array.append('empty') %} {% endfor %}Observe que, no Python, os blocos else são executados sempre que o loop correspondente não tiver sido interrompido por break. Como os loops não podem usar break de qualquer forma, foi escolhido um comportamento ligeiramente diferente para a palavra-chave else.
Também é possível usar loops recursivamente. Isso é útil ao lidar com dados recursivos, como sitemaps ou RDFa. Para usar loops recursivamente, basta adicionar o modificador recursive à definição do loop e chamar a variável loop com o novo iterável no ponto em que deseja fazer a recursão.
O exemplo a seguir implementa um sitemap com loops 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 %}A variável loop sempre se refere ao loop mais próximo (o mais interno). Se tivermos mais de um nível de loops, podemos vincular novamente a variável loop escrevendo {% set outer_loop = loop %} após o loop que queremos usar recursivamente. Então, podemos chamá-lo usando {{ outer_loop(…) }}
Observe que as atribuições em loops serão apagadas ao final da iteração e não podem sobreviver ao escopo do loop. Consulte Atribuições, comportamento de escopo para obter mais informações sobre como lidar com isso.
Se tudo o que você deseja fazer é verificar se algum valor mudou desde a última iteração ou mudará na próxima, você pode usar previtem e 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 %}Se você só se importa em saber se o valor mudou, usar changed é ainda mais fácil:
Python{% for entry in entries %} {% if loop.changed(entry.category) %} <h2>{{ entry.category }}</h2> {% endif %} <p>{{ entry.message }}</p> {% endfor %}
Lista de funções globais
range
Retorna uma lista contendo uma progressão aritmética de inteiros.range(i, j)retorna[i, i+1, i+2, ..., j-1]; o início (!) é definido por padrão como0. Quando step é fornecido, ele especifica o incremento (ou decremento). Por exemplo,range(4)erange(0, 4, 1)retornam[0, 1, 2, 3]. O ponto final é omitido! Esses são exatamente os índices válidos para uma lista de 4 elementos.
Isso é útil para repetir um bloco de modelo várias vezes, por exemplo, para preencher uma lista. Imagine que você tenha 7 usuários na lista, mas queira renderizar três itens vazios para impor uma altura com 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
Gera um lorem ipsum para o modelo. Por padrão, são gerados cinco parágrafos de HTML, cada um com entre 20 e 100 palavras. Se html for False, será retornado texto comum. Isso é útil para gerar conteúdos simples para testes de layout.dict
Uma alternativa conveniente aos literais de dict.{'foo': 'bar'}é igual adict(foo='bar').cycler
Percorre valores, produzindo-os um de cada vez e reiniciando quando chega ao fim.
Semelhante aloop.cycle, mas pode ser usado fora de loops ou entre vários loops. Por exemplo, renderize uma lista de pastas e arquivos alternando entre as classes “odd” e “even”.
Cada argumento posicional será produzido na ordem fornecida em cada ciclo.propriedades
current
Retorna o item atual. Equivale ao item que será retornado na próxima vez que[next()](https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-globals.cycler.next)for chamado.next()
Retorna o item atual e, em seguida, avança[current](https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-globals.cycler.current)para o próximo item.reset()
Redefine o item atual como o primeiro item.
joiner
Um pequeno auxiliar que pode ser usado para “unir” várias seções. Um joiner recebe uma string e retorna essa string sempre que é chamado, exceto na primeira vez (quando retorna uma string vazia). Você pode usá-lo para unir elementos:namespace
Cria um novo contêiner que permite atribuir atributos usando a tag{% set %}:Python{% set ns = namespace() %} {% set ns.foo = 'bar' %}O principal objetivo é permitir transportar um valor de dentro do corpo de um loop para um escopo externo. Os valores iniciais podem ser fornecidos como um dict, como argumentos nomeados ou ambos (mesmo comportamento do construtor dict do 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 (funções)
As macros são comparáveis a funções em linguagens de programação comuns. Elas são úteis para colocar padrões frequentemente usados em funções reutilizáveis e não repetir código (“DRY”).
Veja um pequeno exemplo de uma macro que renderiza um elemento de formulário:
{% 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 %}A macro pode então ser chamada como uma função no 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'}
]Dentro das macros, você tem acesso a três variáveis especiais:
varargs
Se forem passados para a macro mais argumentos posicionais do que ela aceita, eles acabam na variável especial varargs como uma lista de valores.kwargs
Como varargs, mas para argumentos nomeados. Todos os argumentos nomeados não consumidos são armazenados nessa variável especial.caller
Se a macro foi chamada a partir de uma tag call, o chamador é armazenado nessa variável como uma macro chamável.
As macros também expõem alguns de seus detalhes internos. Os seguintes atributos estão disponíveis em um objeto de macro:
nome
O nome da macro.{{ input.name }}imprimiráinput.arguments
Uma tupla com os nomes dos argumentos aceitos pela macro.catch_kwargs
Isso é true se a macro aceitar argumentos nomeados adicionais (ou seja, acessar a variável especial kwargs).catch_varargs
Isso é true se a macro aceitar argumentos posicionais adicionais (ou seja, acessar a variável especial varargs).caller
Isso é true se a macro acessar a variável especial caller e puder ser chamada a partir de uma tag call.
Se o nome de uma macro começar com um sublinhado, ela não será exportada e não poderá ser importada.
Call
Em alguns casos, pode ser útil passar uma macro para outra macro. Para isso, você pode usar o bloco especial call.
Também é possível passar argumentos de volta para o bloco call. Isso o torna útil como substituto para loops. De modo geral, um bloco call funciona exatamente como uma macro sem nome.