Jinja имеет собственный язык шаблонов. Также он называется шаблонизатором. С его помощью можно задавать инструкции, которые помогут автоматизировать создание шаблонов страниц.
Переменные, выражения и вызовы функций
С помощью фигурных скобок в Jinja есть возможность получить результат выражения или переменную. Также можно вызвать функцию и вывести ее значение после того, как содержимое страницы будет выведено в браузере.
Например, так.
Определение выражения
>>> from jinja2 import Template >>> >>> Template("{{ 10 + 3 }}").render() '13' >>> Template("{{ 10 - 3 }}").render() '7' >>> >>> Template("{{ 10 // 3 }}").render() '3' >>> Template("{{ 10 / 3 }}").render() '3.3333333333333335' >>> >>> Template("{{ 10 % 3 }}").render() '1' >>> Template("{{ 10 ** 3 }}").render() '1000' >>>
Внутри выражений также можно использовать и другие операторы сравнения и присваивания. Помимо этого, в них нередко используются логические операторы.
Вывод переменных
Jinja поддерживает как простые переменные, так и сложные типа списков, словарей и кортежей. Также шаблоны могут использовать пользовательские классы и взаимодействовать с ними.
>>> Template("{{ var[1] }}").render(var=[1,2,3]) '2' >>> Template("{{ var['profession'] }}").render(var={'name':'tom', 'age': 25, 'profession': 'Manager' }) 'Manager' >>> Template("{{ var[2] }}").render(var=("c", "c++", "python")) 'python' >>> class Foo: ... def __str__(self): ... return "This is an instance of Foo class" ... >>> Template("{{ var }}").render(var=Foo()) 'This is an instance of Foo class' >>>
Если же приложение попробует обратиться к индексу, которого нет, то в выводе будет просто пустая строка.
>>> Template("{{ var[100] }}").render(var=("c", "c++", "python")) '' >>>
Вызов функции
Также можно использовать для получения значений, которые будут выводиться в шаблоне, функции. Для этого необходимо ее просто вызвать. Вот пример кода, который показывает, как это работает.
>>> def foo(): ... return "foo() called" ... >>> >>> Template("{{ foo() }}").render(foo=foo) 'foo() called' >>>
Атрибуты и методы
Точно так же, как и в Python, чтобы получить доступ к атрибутам и методам объекта, необходимо использовать точку в качестве оператора.
>>> class Foo: ... def __init__(self, i): ... self.i = i ... def do_something(self): ... return "do_something() called" ... >>> >>> Template("{{ obj.i }}").render(obj=Foo(5)) '5' >>> >>> Template("{{ obj.do_something() }}").render(obj=Foo(5)) 'do_something() called' >>>
Комментарии
Шаблонизатор также поддерживает добавление комментариев, которые не читаются кодом программы, а нужны для обозначения того или иного действия. Комментарии могут быть как однострочными, так и многострочными.
{# комментарий #} {# это многострочный комментарий #}
Объявление переменных
Внутри шаблонизатора также можно задавать переменную. Для этого необходимо использовать инструкцию set.
{% set fruit = 'apple' %} {% set name, age = 'Tom', 20 %}
Переменные нужны для того, чтобы хранить результаты сложных операций так, чтобы было возможным их дальнейшее использование в шаблоне. Переменные, определенные за пределами управляющих конструкций ведут себя так же, как и глобальные переменные. К ним можно получить доступ внутри любой структуры.
Но если переменные создаются внутри конструкций, они ведут себя, как локальные. Поэтому за пределами этих конструкций их обнаружить не получится. Это правило не действует лишь в одном случае – если действует инструкция if.
Цикл и условные выражения
Цикл и условные выражения обобщенно называются управляющими конструкциями. Они дают возможность добавлять элементы управления потоком (то есть, условия, при которых выполняются те или иные действия).
Управляющие конструкции выглядят немного по-другому, в них не двойные фигурные скобки, а разделители {% … %}.
Инструкция if
Она работает так же, как и инструкция if в Python. То, что будет выводиться в итоге, зависит от условия, которое действует на данный момент. Например, так.
{% if bookmarks %} <p>User has some bookmarks</p> {% endif %}
Если значение переменной bookmarks – истина, то тогда выводится строка <p>User has some bookmarks</p>.
Важно: если у переменной Jinja отсутствует значение, то ею возвращается значение False.
Помимо этого, возможно использование условий elif, else, как в стандартном коде Python. Например:
{% if user.newbie %} <p>Display newbie stages</p> {% elif user.pro %} <p>Display pro stages</p> {% elif user.ninja %} <p>Display ninja stages</p> {% else %} <p>You have completed all stages</p> {% endif %}
Что касается управляющих инструкций, то они также могут быть вложенными. Например, такими.
{% if user %} {% if user.newbie %} <p>Display newbie stages</p> {% elif user.pro %} <p>Display pro stages</p> {% elif user.ninja %} <p>Display ninja stages</p> {% else %} <p>You have completed all states</p> {% endif %} {% else %} <p>User is not defined</p> {% endif %}
Также возможен тип записи условия и инструкции в одну строку. Это может быть удобно в некоторых ситуациях. Чтобы это сделать, нужно заключить выражение в стандартные двойные фигурные скобки, а не в {% … %}.
Вот пример правильного синтаксиса.
{{ "User is logged in" if loggedin else "User is not logged in" }}
В этом случае, если переменной loggedin возвращается значение True, то выводится строка, что пользователь вошел в аккаунт. В ином же случае будет показано, что человек не произвел ввода в аккаунт.
Что касается условия else, то оно вовсе не обязательно. Если оно не задается, то тогда этим блоком будет возвращен объект undefined.
{{ "User is logged in" if loggedin }}
Здесь, в случае, если переменной loggedin будет возвращено значение True, то тогда выводится строка, информирующая о том, что пользователь вошел в аккаунт. В ином случае не выводится никакого результата.
Точно так же, как и в Python, возможно использование операторов сравнения, присваивания и логических операторов для управляющих конструкций. Все это позволяет реализовать более сложные условия. Вот несколько вариантов.
{# Если user.count ревен 1000, код '<p>User count is 1000</p>' отобразится #} {% if users.count == 1000 %} <p>User count is 1000</p> {% endif %} {# Если выражение 10 >= 2 верно, код '<p>10 >= 2</p>' отобразится #} {% if 10 >= 2 %} <p>10 >= 2</p> {% endif %} {# Если выражение "car" <= "train" верно, код '<p>car <= train</p>' отобразится #} {% if "car" <= "train" %} <p>car <= train</p> {% endif %} {# Если user залогинен и superuser, код '<p>User is logged in and is a superuser</p>' отобразится #} {% if user.loggedin and user.is_superuser %} <p>User is logged in and is a superuser</p> {% endif %} {# Если user является superuser, moderator или author, код '<a href="#">Edit</a>' отобразится #} {% if user.is_superuser or user.is_moderator or user.is_author %} <a href="#">Edit</a> {% endif %} {# Если user и current_user один и тот же объект, код <p>user and current_user are same</p> отобразится #} {% if user is current_user %} <p>user and current_user are same</p> {% endif %} {# Если "Flask" есть в списке, код '<p>Flask is in the dictionary</p>' отобразится #} {% if ["Flask"] in ["Django", "web2py", "Flask"] %} <p>Flask is in the dictionary</p> {% endif %}
Если оказывается, что условие слишком сложное или же просто появляется необходимость в том, чтобы изменить приоритет оператора, то тогда выражение можно обернуть скобками.
{% if (user.marks > 80) and (user.marks < 90) %} <p>You grade is B</p> {% endif %}
Цикл for
Если нужно перебирать последовательность, используется цикл for. Как, например, в этом примере.
{% set user_list = ['tom', 'jerry', 'spike'] %} <ul> {% for user in user_list %} <li>{{ user }}</li> {% endfor %} </ul>
Если запустить страницу, сгенерированную этим кодом, то получим такой результат в выводе.
<ul> <li>tom</li> <li>jerry</li> <li>spike</li> </ul>
А значения словаря перебираются таким способом.
{% set employee = { 'name': 'tom', 'age': 25, 'designation': 'Manager' } %} <ul> {% for key in employee.items() %} <li>{{ key }} : {{ employee[key] }}</li> {% endfor %} </ul>
Внимание! Python не хранит элементы в конкретном порядке. Следовательно, вывод может отличаться.
Если необходимо ключ и значение словаря получить в паре, используется метод items().
{% set employee = { 'name': 'tom', 'age': 25, 'designation': 'Manager' } %} <ul> {% for key, value in employee.items() %} <li>{{ key }} : {{ value }}</li> {% endfor %} </ul>
Цикл for также применяет условие else, точно так же, как и в самом Python. Правда, способ его применения отличается. Необходимо вспомнить, что в Python, если else следует за циклом for, то условие в этом блоке выполняется только после того, как будут перебраны все элементы итерируемого объекта. Или же, если последовательность пуста. Также остановить цикл можно с помощью оператора break, и в этом случае он также не будет выполняться.
Если условие else применяется в цикле for, то его исполнение в Jinja осуществляется лишь при условии, если последовательность пустая или не определена. Например, так.
{% set user_list = [] %} <ul> {% for user in user_list %} <li>{{ user }}</li> {% else %} <li>user_list is empty</li> {% endfor %} </ul>
Аналогично вложенным инструкциям if, можно также циклы for вкладывать друг в друга. Вообще, возможна вложенность любых управляющих конструкций, независимо от того, какие они.
{% for user in user_list %} <p>{{ user.full_name }}</p> <p> <ul class="follower-list"> {% for follower in user.followers %} <li>{{ follower }}</li> {% endfor %} </ul> </p> {% endfor %}
Также циклом for предоставляется специальная переменная, с помощью которой отслеживается прогресс цикла. Вот пример.
<ul> {% for user in user_list %} <li>{{ loop.index }} - {{ user }}</li> {% endfor %} </ul>