Jinja2 Формат Jinja2 Переменные шаблона Jinja могут относиться к любому типу или объекту Python, если их можно преобразовать в строки. Тип модели, списка или словаря можно передать шаблону и отобразить его атрибуты, поместив эти атрибуты во второй блок, указанный ранее.  Виды синтаксиса {% … %} управляющие структуры {{ todo.item }} вывод значений переданных ему выражений {# This is a great API book! #} комментарии Иерархия шаблонов Способ Описание {% include %} Позволяет включить содержимое другого шаблона целиком.

Главная страница

{% include 'partials/header.html' %}

Основное содержимое...

{% extends %} + {% block %} Наследование шаблонов и переопределение блоков.  Базовый шаблон  {% block title %}Default Title{% endblock %} {% block content %}{% endblock %} Дочерний шаблон  {% extends "base.html" %} {% block title %}Custom Title{% endblock %} {% block content %}

Привет, мир!

{% include 'partials/footer.html' %} {% endblock %}   Фильтры {{ variable | filter_name(*args) }} Виды фильтров Название Описание  default(strdefault) Замена вывода переданного значения, если оно оказывается None {{ todo.item | default('This is a default todo item') }} escape Отображение необработанного вывода HTML striptags Удаление HTML тетов перед отправкой int float Преобразование типов перед ответом  {{ 3.142 | int }} 3 {{ 31 | float }} 31.0 join(whitespace) Объединение элементов списка в строку {{ ['Packt', 'produces', 'great', 'books!'] | join(' ') }} Packt produces great books! length Длина переданного объекта Todo count: {{ todos | length }} Todo count: 4 Полный список фильтров Условия: {% if user %}   Hello, {{ user.name }}! {% else %}   Hello, Unknown! {% endif %} Циклы {% for comment in comments %}  {{ comment }} {% endfor %} Можно также обратиться к переменной loop.index для получения дополнительной информации Переменная Описание loop.index Текущее значение итерации (1 - первая итерация) loop.index0 Текущее значение итерации (0 - первая итерация) loop.revindex loop.revindex0 Кол-во оставшихся итераций loop.first True если первая итерация loop.last loop.length loop.pervitem loop.nextitem Значение предыдущей/следующей итерации (пусто если не существует) Макросы: {% macro render_comment(comment) %}    
  • {{ comment }}
  • {% endmacro %} Макросы можно импортировать из файлов {% import 'macros.html' as macros %} В Jinja двойные фигурные скобки {{ }} позволяют получить результат выражение, переменную или вызвать функцию и вывести значение в шаблоне. 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' Если обратится к индексу, который не существует, Jinja просто выведет пустую строку. Вызов функции В Jinja для определения функции ее нужно просто вызвать.  def foo():      return "foo() called" Template("{{ foo() }}").render(foo=foo) 'foo() called' Объявление переменных Внутри шаблона можно задать переменную с помощью инструкции set. {% set fruit = 'apple' %} {% set name, age = 'Tom', 20 %} Переменные определяются для хранения результатов сложных операций, так чтобы их можно было использовать дальше в шаблоне. Переменные, определенные вне управляющих конструкций (о них дальше), ведут себя как глобальные переменные и доступны внутри любой структуры. Тем не менее переменные, созданные внутри конструкций, ведут себя как локальные переменные и видимы только внутри этих конкретных конструкций. Единственное исключение — инструкция if. Цикл и условные выражения Реклама Управляющие конструкции позволяют добавлять в шаблоны элементы управления потоком и циклы. По умолчанию, управляющие конструкции используют разделитель {% … %} вместо двойных фигурных скобок {{ ... }}. Инструкция if Инструкция if в Jinja имитирует выражение if в Python, а значение условия определяет набор инструкции. Например: {% if bookmarks %}    

    User has some bookmarks

    {% endif %} Если значение переменной bookmarks – True, тогда будет выведена строка

    User has some bookmarks

    . Стоит запомнить, что в Jinja, если у переменной нет значения, она возвращает False. Также можно использовать условия elif и else, как в обычном коде Python. Например: {% if user.newbie %}    

    Display newbie stages

    {% elif user.pro %}    

    Display pro stages

    {% elif user.ninja %}    

    Display ninja stages

    {% else %}    

    You have completed all stages

    {% endif %} Управляющие инструкции также могут быть вложенными. Например: {% if user %}     {% if user.newbie %}        

    Display newbie stages

        {% elif user.pro %}        

    Display pro stages

        {% elif user.ninja %}        

    Display ninja stages

        {% else %}        

    You have completed all states

        {% endif %} {% else %}    

    User is not defined

    {% endif %} Реклама В определенных случаях достаточно удобно записывать инструкцию if в одну строку. Jinja поддерживает такой тип записи, но называет это выражением if, потому что оно записывается с помощью двойных фигурных скобок {{ … }}, а не {% … %}. Например: {{ "User is logged in" if loggedin else "User is not logged in" }} Здесь если переменная loggedin вернет True, тогда будет выведена строка “User is logged in”. В противном случае — “User is not logged in”. Условие else использовать необязательно. Если его нет, тогда блок else вернет объект undefined. {{ "User is logged in" if loggedin }} Здесь, если переменная loggedin вернет True, будет выведена строка “User is logged in”. В противном случае — ничего. Как и в Python можно использовать операторы сравнения, присваивания и логические операторы для управляющих конструкций, чтобы создавать более сложные условия. Вот несколько примеров: {# Если user.count ревен 1000, код '

    User count is 1000

    ' отобразится #} {% if users.count == 1000 %}    

    User count is 1000

    {% endif %} {# Если выражение 10 >= 2 верно, код '

    10 >= 2

    ' отобразится #} {% if 10 >= 2 %}    

    10 >= 2

    {% endif %} {# Если выражение "car" <= "train" верно, код '

    car <= train

    ' отобразится #} {% if "car" <= "train" %}    

    car <= train

    {% endif %} {#     Если user залогинен и superuser, код     '

    User is logged in and is a superuser

    ' отобразится #} {% if user.loggedin and user.is_superuser %}    

    User is logged in and is a superuser

    {% endif %} {#     Если user является superuser, moderator или author, код     'Edit' отобразится #} {% if user.is_superuser or user.is_moderator or user.is_author %}     Edit {% endif %} {#     Если user и current_user один и тот же объект, код     

    user and current_user are same

    отобразится #} {% if user is current_user %}    

    user and current_user are same

    {% endif %} {#     Если "Flask" есть в списке, код      '

    Flask is in the dictionary

    ' отобразится #} {% if ["Flask"] in ["Django", "web2py", "Flask"] %}    

    Flask is in the dictionary

    {% endif %} Если условия становятся слишком сложными, или просто есть желание поменять приоритет оператора, можно обернуть выражения скобками (): {% if (user.marks > 80) and (user.marks < 90) %}    

    You grade is B

    {% endif %} Цикл for Цикл for позволяет перебирать последовательность. Например: {% set user_list = ['tom', 'jerry', 'spike'] %} Вывод: Вот как можно перебирать значения словаря: {% set employee = { 'name': 'tom', 'age': 25, 'designation': 'Manager' } %} Вывод: Примечание: в Python элементы словаря не хранятся в конкретном порядке, поэтому вывод может отличаться. Если нужно получить ключ и значение словаря вместе, используйте метод items(). {% set employee = { 'name': 'tom', 'age': 25, 'designation': 'Manager' } %} Вывод: Цикл for также может использовать дополнительное условие else, как в Python, но зачастую способ его применения отличается. Стоит вспомнить, что в Python, если else идет следом за циклом for, условие else выполняется только в том случае, если цикл завершается после перебора всей последовательности, или если она пуста. Оно не выполняется, если цикл остановить оператором break. Когда условие else используется в цикле for в Jinja, оно исполняется только в том случае, если последовательность пустая или не определена. Например: Реклама {% set user_list = [] %} Вывод: По аналогии с вложенными инструкциями if, можно использовать вложенные циклы for. На самом деле, любые управляющие конструкции можно вкладывать одна в другую. {% for user in user_list %}    

    {{ user.full_name }}

       

           

       

    {% endfor %} Цикл for предоставляет специальную переменную loop для отслеживания прогресса цикла. Например: loop.index внутри цикла for начинает отсчет с 1. В таблице упомянуты остальные широко используемые атрибуты переменной loop. Метод Значение loop.index0 то же самое что и loop.index, но с индексом 0, то есть, начинает считать с 0, а не с 1. loop.revindex возвращает номер итерации с конца цикла (считает с 1). loop.revindex0 возвращает номер итерации с конца цикла (считает с 0). loop.first возвращает True, если итерация первая. В противном случае — False. loop.last возвращает True, если итерация последняя. В противном случае — False. loop.length возвращает длину цикла(количество итераций). Примечание: полный список есть в документации Flask. Фильтры Фильтры изменяют переменные до процесса рендеринга. Синтаксис использования фильтров следующий: variable_or_value|filter_name Вот пример: {{ comment|title }} Фильтр title делает заглавной первую букву в каждом слове. Если значение переменной comment — "dust in the wind", то вывод будет "Dust In The Wind". Можно использовать несколько фильтров, чтобы точнее настраивать вывод. Например: {{ full_name|striptags|title }} Фильтр striptags удалит из переменной все HTML-теги. В приведенном выше коде сначала будет применен фильтр striptags, а затем — title. У некоторых фильтров есть аргументы. Чтобы передать их фильтру, нужно вызвать фильтр как функцию. Например: {{ number|round(2) }} Фильтр round округляет число до конкретного количества символов. В следующей таблице указаны широко используемые фильтры. Название Описание upper делает все символы заглавными lower приводит все символы к нижнему регистру capitalize делает заглавной первую букву и приводит остальные к нижнему регистру escape экранирует значение safe предотвращает экранирование length возвращает количество элементов в последовательности trim удаляет пустые символы в начале и в конце random возвращает случайный элемент последовательности Примечание: полный список фильтров доступен здесь. Макросы Макросы в Jinja напоминают функции в Python. Суть в том, чтобы сделать код, который можно использовать повторно, просто присвоив ему название. Например: {% macro render_posts(post_list, sep=False) %}    
            {% for post in post_list %}            

    {{ post.title }}

               
                    {{ post.html|safe }}            
            {% endfor %}         {% if sep %}
    {% endif %}    
    {% endmacro %} В этом примере создан макрос render_posts, который принимает обязательный аргумент post_list и необязательный аргумент sep. Использовать его нужно следующим образом: {{ render_posts(posts) }} Определение макроса должно идти до первого вызова, иначе выйдет ошибка. Реклама Вместо того чтобы использовать макросы прямо в шаблоне, лучше хранить их в отдельном файле и импортировать по надобности. Предположим, все макросы хранятся в файле macros.html в папке templates. Чтобы импортировать их из файла, нужно использовать инструкцию import: {% import "macros.html" as  macros %} Теперь можно ссылаться на макросы в файле macros.html с помощью переменной macros. Например: {{ macros.render_posts(posts) }} Инструкция {% import “macros.html” as macros %} импортирует все макросы и переменные (определенные на высшем уровне) из файла macros.html в шаблон. Также можно импортировать определенные макросы с помощью from: {% from "macros.html" import render_posts %} При использовании макросов будут ситуации, когда потребуется передать им произвольное число аргументов. По аналогии с *args и **kwargs в Python внутри макросов можно получить доступ к varargs и kwargs. varags: сохраняет дополнительные позиционные аргументы, переданные макросу, в виде кортежа. lwargs: сохраняет дополнительные позиционные аргументы, переданные макросу, в виде словаря. Хотя к ним можно получить доступ внутри макроса, объявлять их отдельно в заголовке макроса не нужно. Вот пример: {% macro custom_renderer(para) %}    

    {{ para }}

       

    varargs: {{ varargs }}

       

    kwargs: {{ kwargs }}

    {%  endmacro  %} {{ custom_renderer("some content", "apple", name='spike', age=15) }} В этом случае дополнительный позиционный аргумент, "apple", присваивается varargs, а дополнительные аргументы-ключевые слова (name=’spike’, age=15) — kwargs. Экранирование Jinja по умолчанию автоматически экранирует вывод переменной в целях безопасности. Поэтому если переменная содержит, например, такой HTML-код: "

    Escaping in Jinja

    ", он отрендерится в виде "<p>Escaping in Jinja</p>". Благодаря этому HTML-коды будут отображаться в браузере, а не интерпретироваться. Если есть уверенность, что данные безопасны и их точно можно рендерить, стоит воспользоваться фильтром safe. Например: {% set html = "

    Escaping in Jinja

    " %} {{ html|safe }} Вывод:

    Escaping in Jinja

    Использовать фильтр safe в большом блоке кода будет неудобно, поэтому в Jinja есть оператор autoescape, который используется, чтобы отключить экранирование для большого объема данных. Он может принимать аргументы true или false для включения и отключения экранирования, соответственно. Например: {% autoescape true %}     Escaping enabled {% endautoescape %} {% autoescape false %}     Escaping disabled {% endautoescape %} Все между {% autoescape false %} и {% endautoescape %} отрендерится без экранирования символов. Если нужно экранировать отдельные символы при выключенном экранировании, стоит использовать фильтр escape. Например: {% autoescape false %}    
            {% for post in post_list %}            

    {{ post.title }}

               
                    {{ post.html }}            
            {% endfor %}    
       
            {% for comment in comment_list %}            

    {{ comment|escape }}

    # escaping is on for comments         {% endfor %}    
    {% endautoescape %} Вложенные шаблоны Инструкция include рендерит шаблон внутри другого шаблона. Она широко используется, чтобы рендерить статический раздел, который повторяется в разных местах сайта. Вот синтаксис include: Предположим, что навигационное меню хранится в файле nav.html, сохраненном в папке templates: Чтобы добавить это меню в home.html, нужно использовать следующий код:         Title     {# добавляем панель навигации из nav.html #}     {% include 'nav.html' %} Вывод:         Title Наследование шаблонов Наследование шаблонов — один из самых мощных элементов шаблонизатора Jinja. Его принцип похож на ООП (объектно-ориентированное программирование). Все начинается с создания базового шаблона, который содержит в себе скелет HTML и отдельные маркеры, которые дочерние шаблоны смогут переопределять. Маркеры создаются с помощью инструкции block. Дочерние шаблоны используют инструкцию extends для наследования или расширения основного шаблона. Вот пример: {# Это шаблон templates/base.html #}         {% block title %}Default Title{% endblock %}     {% block nav %}             {% endblock %}       {% block content %}       {% endblock %} Это базовый шаблон base.html. Он создает три блока с помощью block, которые впоследствии будут заполнены дочерними шаблонами. Инструкция block принимает один аргумент — название блока. Внутри шаблона это название должно быть уникальным, иначе возникнет ошибка. Дочерний шаблон — это шаблон, который растягивает базовый шаблон. Он может добавлять, перезаписывать или оставлять элементы родительского блока. Вот как можно создать дочерний шаблон. {# Это шаблон templates/child.html #} {% extends 'base.html' %} {% block content %}     {% for bookmark in bookmarks %}        

    {{ bookmark.title }}

        {% endfor %} {% endblock %} Инструкция extends сообщает Jinja, что child.html — это дочерний элемент, наследник base.html. Когда Jinja обнаруживает инструкцию extends, он загружает базовый шаблон, то есть base.html, а затем заменяет блоки контента внутри родительского шаблона блоками с теми же именами из дочерних шаблонов. Если блок с соответствующим названием не найден, используется блок родительского шаблона. Стоит отметить, что в дочернем шаблоне перезаписывается только блок content, так что содержимое по умолчанию из title и nav будет использоваться при рендеринге дочернего шаблона. Вывод должен выглядеть следующим образом: Реклама         Default Title        

    Bookmark title 1

       

    Bookmark title 2

       

    Bookmark title 3

       

    Bookmark title 4

    Если нужно, можно поменять заголовок по умолчанию, переписав блок title в child.html: {# Это шаблон templates/child.html #} {% extends 'base.html' %} {% block title %}     Child Title {% endblock %} {% block content %}     {% for bookmark in bookmarks %}        

    {{ bookmark.title }}

        {% endfor %} {% endblock %} После перезаписи блока на контент из родительского шаблона все еще можно ссылаться с помощью функции super(). Обычно она используется, когда в дополнение к контенту дочернего шаблона нужно добавить содержимое из родительского. Например: {# Это шаблон templates/child.html #} {% extends 'base.html' %} {% block title %}     Child Title {% endblock %} {% block nav %}     {{ super() }} {# referring to the content in the parent templates #}    
  • Contact
  •    
  • Career
  • {% endblock %} {% block content %}     {% for bookmark in bookmarks %}        

    {{ bookmark.title }}

        {% endfor %} {% endblock %} Вывод:         Child Title        

    Bookmark title 1

       

    Bookmark title 2

       

    Bookmark title 3

       

    Bookmark title 4