Сообщить об ошибке.

Общий синтаксис шаблона jinja2 в Python

Шаблон Jinja2 - это просто текстовый файл. Модуль Jinja2 может генерировать любой текстовый формат (HTML, XML, CSV, LaTeX и т. д.). Шаблон Jinja не обязательно должен иметь конкретное расширение: вполне подойдет .html, .xml или любое другое расширение.

Шаблон содержит переменные и/или выражения, которые заменяются значениями при визуализации шаблона, также применяются теги, управляющие логикой шаблона. Синтаксис шаблона во многом вдохновлен Django и Python.

Ниже приведен минимальный шаблон, который иллюстрирует некоторые основы использования конфигурации Jinja по умолчанию.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>My Webpage</title>
</head>
<body>
    <ul id="navigation">
    {% for item in navigation %}
        <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    {% endfor %}
    </ul>

    <h1>My Webpage</h1>
    {{ a_variable }}

    {# a comment #}
</body>
</html>

В примере показаны параметры конфигурации по умолчанию. Разработчик приложения может изменить конфигурацию синтаксиса с {% foo %} на <% foo %> или что-то подобное.

Есть несколько видов разделителей. Разделители Jinja по умолчанию настроены следующим образом:

Содержание:


Расширение файла шаблона Jinja.

Как сказано выше, файл с любым расширением может быть загружен в качестве шаблона. Добавление расширения .jinja, такого как user.html.jinja, может облегчить работу некоторых IDE или плагинов, используемых редактором кода. Автоэкранирование HTML, может применяться на основе расширения файла, в этом случае необходимо будет учитывать дополнительный суффикс.

Еще одна хорошая эвристика для идентификации шаблонов заключается в том, что по умолчанию они находятся в папке templates, независимо от расширения. Это общий макет для проектов.

Переменные и выражения в шаблонах Jinja.

Переменные шаблона определяются контекстным словарем, переданным в шаблон при помощи метода Template.render().

Переменные могут иметь атрибуты или элементы, к которым можно получить доступ в шаблонах. Какие атрибуты имеют переменные, сильно зависит от приложения, предоставляющего эту переменную.

В шаблонах можно использовать точку (.) для доступа к атрибутам переменной в дополнение к стандартному синтаксису индексирования ([]) в Python __getitem__().

Следующие строки делают одно и то же:

{{ foo.bar }}
{{ foo['bar'] }}

Важно понимать, что внешние двойные фигурные скобки {{ ... }} не являются частью переменной, а являются частью оператора шаблона для вывода переменной/выражения на печать. Если нужно обратится к переменным внутри тегов {% ... %}, например при использовании в цикле шаблона {% for item in items %}, то не заключайте переменные в фигурные скобки.

Если переменная или атрибут не существует в контексте шаблона, то на выходе получите неопределенное значение Undefined. То, что можно сделать с таким значением, зависит от конфигурации приложения: поведение по умолчанию значения Undefined это возврат пустой строки ''.

Реализация

Для удобства выражение foo.bar в Jinja выполняет следующие действия на слое Python:

  • проверяет наличие атрибута getattr(foo, 'bar'),
  • если нет, то проверяет наличие элемента foo.__getitem__('bar'),
  • если его нет, то возвращает неопределенный объект Undefined.

Выражение foo['bar'] работает в основном так же с небольшой разницей в последовательности:

  • проверяет наличие элемента foo.__getitem__('бар'),
  • если его нет, проверяет наличие атрибута getattr(foo, 'bar'),
  • если его нет, то возвращает неопределенный объект Undefined.

Это важно, если объект имеет элемент и атрибут с одинаковым именем. Кроме того, фильтр attr() ищет только атрибуты.

Использование методов, определенных для типа Python.

В шаблонах Jinja2 можно использовать любой из методов, определенных для типа переменной. Значение, возвращаемое при вызове метода, используется как значение выражения. Вот пример, в котором используются методы, определенные для строк, где page.title - это строка:

{{ page.title.capitalize() }}

Это работает для методов с пользовательскими типами. Например, если для переменной foo типа Foo определен метод bar, то можно сделать следующее:

{{ foo.bar(value) }}

Операторы Python работают также, как и ожидается. Например, оператор Python % реализует для строк стиль printf:

{{ "Hello, %s!" % name }}

Хотя в этом случае лучше использовать метод строки str.format(), который немного надуман в контексте рендеринга шаблона:

{{ "Hello, {}!".format(name) }}

Использование фильтров в шаблонах Jinja.

Переменные можно изменять с помощью фильтров. Фильтры отделяются от переменной вертикальной чертой (|) и могут иметь необязательные аргументы в круглых скобках. Можно объединить несколько фильтров. Выходные данные одного фильтра применяются к следующему.

Например, выражение шаблона {{ name|striptags|title }} удалит все HTML-теги из переменной name и напечатает все слова с заглавной буквы. Вызов последовательности фильтров будет следующим title(striptags(name)).

Фильтры, которые принимают аргументы, заключают аргументы в круглые скобки, как и при вызове функции Python. Например: выражение шаблона {{ listx|join(',') }} объединит список строк listx в одну строку, а в качестве разделителя будет использовать запятую ', '. Вызов фильтра будет следующим join(listx, ',').

В шаблонах jinja2 дополнительно можно использовать разделы фильтров, которые позволяют применять фильтры к блоку данных шаблона.

{% filter upper %}
    Этот текст становится прописным
{% endfilter %}

Дополнительно смотрите список всех встроенных фильтров с их описанием и примерами использования в шаблонах, а также как создать и зарегистрировать свои собственные фильтры.

Использование тестов в шаблонах Jinja.

Помимо фильтров, доступны так называемые тесты. Тесты можно использовать для проверки переменной на соответствие общему выражению. Чтобы проверить переменную или выражение, необходимо добавить после переменной is плюс имя теста. Например, чтобы узнать, определена ли переменная, можно написать что то на подобное name is defined, которое затем вернет истину или ложь в зависимости от того, определено ли name в текущем контексте шаблона.

Тесты тоже могут принимать аргументы. Если тест принимает только один аргумент, то скобки можно опустить. Например, следующие два выражения делают одно и то же:

{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}

Дополнительно смотрите список всех встроенных тестов с их описанием и примерами использования в шаблонах.

Комментарии в шаблонах Jinja.

Чтобы закомментировать часть строки в шаблоне, используйте синтаксис комментария, который по умолчанию установлен на {# ... #}. Это полезно, чтобы закомментировать части шаблона для отладки или добавить информацию для других разработчиков шаблона, а также для себя:

{# note: commented-out template because we no longer use this
    {% for user in users %}
        ...
    {% endfor %}
#}

Управление пробелами в шаблонах Jinja.

В конфигурации по умолчанию:

  • Один завершающий символ новой строки удаляется, если он присутствует.
  • Другие пробелы (пробелы, табуляции, новые строки и т. д.) возвращаются без изменений.

Если настроить модуль Jinja при создании Environment с аргументом trim_blocks, то первая новая строка после тега шаблона {% .. %} удаляется автоматически. Также в Environment может быть установлен аргумент lstrip_blocks для удаления табуляции и пробелов от начала строки до начала блока {% .. %} (ничего не будет удалено, если перед началом блока есть другие символы).

Если включены как trim_blocks, так и lstrip_blocks, то можно помещать теги блоков в их собственные строки, и вся строка блока будет удалена при рендеринге, сохраняя пробелы в содержимом. Например, без установленных аргументов trim_blocks и lstrip_blocks этот шаблон:

<div>
    {% if True %}
        Привет
    {% endif %}
</div>

Отображается с пустыми строками внутри div:

<div>

        Привет

</div>

Но при включенных аргументах trim_blocks и lstrip_blocks строки блока шаблона удаляются, а остальные пробелы сохраняются:

<div>
        Привет
</div>

Можно вручную отключить поведение lstrip_blocks, поставив знак плюса (+) в начале блока:

<div>
        {%+ if something %}Привет{% endif %}
</div>

Также можно удалить пробелы в шаблонах вручную. Если добавить знак минус (-) в начало или конец блока (например, тега шаблона for/in), комментария или выражения переменной, то пробелы до или после этого блока будут удалены:

{% for item in seq -%}
    {{ item }}
{%- endfor %}

Эта разметка шаблона напечатает все элементы без пробелов между ними. Если бы переменная seq была списком чисел от 1 до 9, то на выходе было бы напечатано 123456789.

Если включены строчные операторы, то они автоматически удаляют начальные пробелы до начала строки.

По умолчанию Jinja также удаляет завершающие символы новой строки. Чтобы сохранить одиночные завершающие символы новой строки, настройте Environment с аргументом keep_trailing_newline=True.

Примечание: НЕ НАДО добавлять пробелы между тегом и знаком минус.

Правильная запись:
{%- if foo -%}...{% endif %}

НЕ правильная запись:
{% - if foo - %}...{% endif %}

Необрабатываемые блоки шаблонов Jinja.

Иногда желательно (даже необходимо) чтобы модуль Jinja игнорировал части, которые в противном случае обрабатывались как переменные или блоки. Например, если с синтаксисом по умолчанию необходимо использовать парные фигурные скобки {{ как необработанную строку в шаблоне, то самый простой способ это сделать - использовать выражение переменной {{ '{{' }}

Для больших разделов имеет смысл пометить блок как необработанный. Например, чтобы включить пример синтаксиса Jinja в шаблон, можно использовать фрагмент:

{% raw %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

Примечание. Знак минус в конце тега {% raw -%} очищает все пробелы и символы новой строки, предшествующие первому символу необработанных данных.

Строчные операторы и комментарии в шаблонах.

Если в приложении разрешены строчные операторы, то можно пометить строку как оператор. Например, если при инициализации окружения Environment, для аргумента line_statement_prefix задано значение '#', то следующие два примера эквивалентны:

<ul>
# for item in seq
    <li>{{ item }}</li>
# endfor
</ul>

<ul>
{% for item in seq %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

Префикс строки для оператора может появляться в любом месте строки, если ему не предшествует текст. Для удобства чтения операторы, которые начинают блок (например, for, if, elif и т. д.), могут заканчиваться двоеточием:

# for item in seq:
    ...
# endfor

Примечание. Строчные операторы могут охватывать несколько строк, если есть открытые круглые скобки (), фигурные скобки {} или квадратные скобки []:

<ul>
# for href, caption in [('index.html', 'Index'),
                        ('about.html', 'About')]:
    <li><a href="{{ href }}">{{ caption }}</a></li>
# endfor
</ul>

Начиная с Jinja 2.2, также доступны построчные комментарии. Например, если окружение Environment настроено с аргументом line_comment_prefix='##', то все от символов ## до конца строки игнорируется (за исключением знака новой строки):

# for item in seq:
    <li>{{ item }}</li>     ## Этот комментарий игнорируется
# endfor

Область с ограниченной видимостью в шаблоне Jinja.

Оператор шаблона with позволяет создать новую внутреннюю область видимости. Переменные, установленные в этой области, не видны за пределами области.

В двух словах:

{% with %}
    {% set foo = 42 %}
    {# здесь переменная `foo` будет равна 42 #}
    {{ foo }}
{% endwith %}
{# здесь переменная `foo` будет не определена #}

Так как обычно переменные устанавливаются в начале области видимости, это можно сделать с помощью оператора шаблона with. Следующие два примера эквивалентны:

{% with foo = 42 %}
    {{ foo }}
{% endwith %}

{% with %}
    {% set foo = 42 %}
    {{ foo }}
{% endwith %}

В версиях Jinja до 2.9 обращение одной переменной к другой имело непредвиденные последствия. В частности, одна переменная может ссылаться на другую, определенную в той же теге шаблона with, что вызвало проблемы и с тех пор было улучшено. В частности, в более новых версиях Jinja следующий код всегда ссылается на переменную a извне блока with:

{% with a={}, b=a.attribute %}...{% endwith %}

В более ранних версиях Jinja атрибут b будет относиться к результатам первого атрибута. Если код зависит от этого поведения, то можно переписать его, чтобы использовать тег шаблона set:

{% with a={} %}
    {% set b = a.attribute %}
{% endwith %}

Примечание. В более старых версиях Jinja до 2.9 требовалось включить эту функцию с помощью расширения. Теперь эта функциональность включена по умолчанию.

Переопределение автоэкранирования HTML в шаблоне Jinja.

При желании можно активировать и деактивировать автоматическое экранирование HTML прямо из шаблонов.

{% autoescape true %}
    В этом блоке активно автоэкранирование
{% endautoescape %}

{% autoescape false %}
    В этом блоке автоэкранирование неактивно
{% endautoescape %}

После блока autoescape поведение возвращается к тому, что было раньше.

Примечание. В более старых версиях Jinja до 2.9 требовалось включить эту функцию с помощью расширения. Теперь эта функциональность включена по умолчанию.