Документация по шаблонизатору
В этом документе описывается синтаксис и семантика механизма шаблонизации, и он будет наиболее полезен в качестве справочника для тех, кто создает шаблоны Jinja. Поскольку механизм шаблонизации очень гибкий, конфигурация приложения может немного отличаться от представленного здесь кода с точки зрения разделителей и поведения неопределенных значений.
Краткое описание
Шаблон Jinja — это просто текстовый файл. Jinja может генерировать любой текстовый формат (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, например user.html.jinja, может упростить работу для некоторых IDE или плагинов редактора, но это не обязательно. Автоматическое экранирование, о котором будет рассказано позже, может применяться на основе расширения файла, поэтому в этом случае необходимо учитывать дополнительный суффикс.
Еще одна хорошая эвристика для идентификации шаблонов заключается в том, что они находятся в папке templates, независимо от расширения. Это распространенная структура для проектов.
Переменные
Переменные шаблона определяются контекстным словарем, передаваемым в шаблон.
Вы можете работать с переменными в шаблонах при условии, что они передаются приложением. Переменные могут иметь атрибуты или элементы, к которым вы также можете получить доступ. То, какие атрибуты имеет переменная, во многом зависит от приложения, предоставляющего эту переменную.
Вы можете использовать точку (.) для доступа к атрибутам переменной в дополнение к стандартному синтаксису «индексации» Python __getitem__ ([]).
Следующие строки делают одно и то же:
{{ foo.bar }}
{{ foo['bar'] }}
Важно знать, что внешние двойные фигурные скобки не являются частью переменной, а оператором печати. Если вы обращаетесь к переменным внутри тегов, не ставьте скобки вокруг них.
Если переменная или атрибут не существует, вы получите неопределенное значение. То, что вы можете сделать с таким значением, зависит от конфигурации приложения: поведение по умолчанию — вычислять пустую строку при печати или итерации и вызывать ошибку для всех остальных операций.
Реализация
Для удобства, foo.bar в Jinja делает следующее на уровне Python:
- проверяет наличие атрибута с именем
barуfoo(getattr(foo, 'bar')) - если его нет, проверяет наличие элемента
'bar'вfoo(foo.__getitem__('bar')) - если его нет, возвращает неопределенный объект.
foo['bar'] работает в основном так же, с небольшим отличием в последовательности:
- проверяет наличие элемента
'bar'вfoo. (foo.__getitem__('bar')) - если его нет, проверяет наличие атрибута с именем
barуfoo. (getattr(foo, 'bar')) - если его нет, возвращает неопределенный объект.
Это важно, если объект имеет элемент и атрибут с одинаковым именем. Кроме того, фильтр attr() ищет только атрибуты.
Фильтры
Переменные могут быть изменены с помощью фильтров. Фильтры отделяются от переменной символом трубы (|) и могут иметь необязательные аргументы в скобках. Можно цеплять несколько фильтров. Результат работы одного фильтра применяется к следующему.
Например, {{ name|striptags|title }} удалит все HTML-теги из переменной name и переведет вывод в заголовок (title(striptags(name))).
Фильтры, которые принимают аргументы, имеют скобки вокруг аргументов, как и вызов функции. Например: {{ listx|join(', ') }} соединит список запятыми (str.join(', ', listx)).
В списке встроенных фильтров, приведенном ниже, описаны все встроенные фильтры.
Тесты
Помимо фильтров, доступны так называемые «тесты». Тесты можно использовать для проверки переменной на соответствие общему выражению. Чтобы проверить переменную или выражение, добавьте is плюс имя теста после переменной. Например, чтобы узнать, определена ли переменная, вы можете сделать name is defined, что вернет true или false в зависимости от того, определена ли name в текущем контексте шаблона.
Тесты также могут принимать аргументы. Если тест принимает только один аргумент, вы можете опустить скобки. Например, следующие два выражения делают одно и то же:
{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}
В списке встроенных тестов, приведенном ниже, описаны все встроенные тесты.
Комментарии
Чтобы закомментировать часть строки в шаблоне, используйте синтаксис комментариев, который по умолчанию установлен как {# ... #}. Это полезно для комментирования частей шаблона для отладки или для добавления информации для других разработчиков шаблонов или для себя:
{# note: commented-out template because we no longer use this
{% for user in users %}
...
{% endfor %}
#}
Управление пробелами
В конфигурации по умолчанию:
- удаляется единственная завершающая строка перевода каретки, если она присутствует
- другие пробелы (пробелы, табуляции, переводы строки и т. д.) возвращаются без изменений
Если приложение настраивает Jinja на trim_blocks, первый перевод строки после тега шаблона удаляется автоматически (как в PHP). Опция lstrip_blocks также может быть установлена для удаления табуляций и пробелов от начала строки до начала блока. (Ничего не будет удалено, если перед началом блока есть другие символы.)
С включенными trim_blocks и lstrip_blocks, вы можете размещать теги блоков на отдельных строках, и вся строка блока будет удалена при рендеринге, сохраняя пробелы содержимого. Например, без опций trim_blocks и lstrip_blocks, этот шаблон:
<div>
{% if True %}
yay
{% endif %}
</div>
рендерится с пустыми строками внутри div:
<div>
yay
</div>
Но с включенными trim_blocks и lstrip_blocks, строки блоков шаблона удаляются, а другие пробелы сохраняются:
<div>
yay
</div>
Вы можете вручную отключить поведение lstrip_blocks поставив знак плюс (+) в начале блока:
<div>
{%+ if something %}yay{% endif %}
</div>
Вы также можете вручную удалять пробелы в шаблонах. Если вы добавите знак минус (-) в начало или конец блока (например, тега For), комментария или выражения переменной, пробелы до или после этого блока будут удалены:
{% for item in seq -%}
{{ item }}
{%- endfor %}
Это приведет к тому, что все элементы будут без пробелов между ними. Если seq был бы списком чисел от 1 до 9, вывод был бы 123456789.
Если включены Операторы в строке, они автоматически удаляют ведущие пробелы до начала строки.
По умолчанию Jinja также удаляет завершающие переводы строки. Чтобы сохранить единственные завершающие переводы строк, настройте Jinja на keep_trailing_newline.
Примечание
Нельзя добавлять пробелы между тегом и знаком минус.
верно:
{%- if foo -%}...{% endif %}
неверно:
{% - if foo - %}...{% endif %}
Экранирование
Иногда желательно — даже необходимо — чтобы Jinja игнорировал части, которые он в противном случае обрабатывал бы как переменные или блоки. Например, если, с синтаксисом по умолчанию, вы хотите использовать {{ как необработанную строку в шаблоне и не начинать переменную, вам нужно использовать трюк.
Самый простой способ вывести литеральный разделитель переменной ({{) — это использовать выражение переменной:
{{ '{{' }}
Для больших разделов имеет смысл пометить блок raw. Например, чтобы включить пример синтаксиса Jinja в шаблон, вы можете использовать этот фрагмент:
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
Примечание
Знак минус в конце тега {% raw -%} очищает все пробелы и переводы строк перед первым символом ваших необработанных данных.
Операторы в строке
Если операторы в строке включены приложением, можно пометить строку как оператор. Например, если префикс оператора в строке настроен на #, следующие два примера эквивалентны:
<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, доступны также комментарии на основе строк. Например, если префикс комментария в строке настроен на ##, все от ## до конца строки игнорируется (за исключением знака перевода строки):
# for item in seq:
<li>{{ item }}</li> ## this comment is ignored
# endfor
Наследование шаблонов
Самая мощная часть Jinja — это наследование шаблонов. Наследование шаблонов позволяет создавать базовый шаблон «скелета», который содержит все общие элементы вашего сайта и определяет блоки, которые могут быть переопределены дочерними шаблонами.
Звучит сложно, но на самом деле очень просто. Легче всего понять это, начав с примера.
Базовый шаблон
Этот шаблон, который мы назовем base.html, определяет простой HTML-скелет документа, который вы можете использовать для простой двухколоночной страницы. Задача «дочерних» шаблонов — заполнить пустые блоки контентом:
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2008 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
</html>
В этом примере теги {% block %} определяют четыре блока, которые могут заполнять дочерние шаблоны. Всё, что делает тег block, — это сообщает механизму обработки шаблонов, что дочерний шаблон может переопределить эти заполнители в шаблоне.
Теги block могут находиться внутри других блоков, таких как if, но они всегда будут выполняться независимо от того, отображается ли блок if.
Дочерний шаблон
Дочерний шаблон может выглядеть так:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}
Тег {% extends %} является здесь ключевым. Он сообщает механизму обработки шаблонов, что этот шаблон «расширяет» другой шаблон. Когда система шаблонов вычисляет этот шаблон, она сначала находит родительский. Тег extends должен быть первым тегом в шаблоне. Всё, что находится перед ним, выводится нормально и может вызвать путаницу. Для получения подробной информации об этом поведении и о том, как использовать его в своих интересах, см. Null-Master Fallback. Также блок всегда будет заполнен независимо от того, вычисляется ли окружающее условие как истинное или ложное.
Имя файла шаблона зависит от загрузчика шаблонов. Например, FileSystemLoader позволяет вам получать доступ к другим шаблонам, указывая имя файла. Вы можете получать доступ к шаблонам в подкаталогах с помощью слеша:
{% extends "layout/default.html" %}
Но это поведение может зависеть от приложения, встраивающего Jinja. Обратите внимание, что поскольку дочерний шаблон не определяет блок footer, вместо него используется значение из родительского шаблона.
Вы не можете определять несколько тегов {% block %} с одинаковым именем в одном шаблоне. Это ограничение существует потому, что тег блока работает в «обоих» направлениях. То есть тег блока не только предоставляет заполняемое место — он также определяет содержимое, которое заполняет это место в родительском. Если бы в шаблоне было два тега {% block %} с одинаковым именем, родительский шаблон не знал бы, содержимое какого из блоков использовать.
Если вы хотите вывести блок несколько раз, вы можете, однако, использовать специальную переменную self и вызвать блок с этим именем:
<title>{% block title %}{% endblock %}</title>
<h1>{{ self.title() }}</h1>
{% block body %}{% endblock %}
Суперблоки
Можно отобразить содержимое родительского блока, вызвав super(). Это возвращает результаты родительского блока:
{% block sidebar %}
<h3>Table Of Contents</h3>
...
{{ super() }}
{% endblock %}
Вложенные extends
В случае нескольких уровней {% extends %}, ссылки super могут быть связаны (как в super.super()) для пропуска уровней в дереве наследования.
Например:
# parent.tmpl
body: {% block body %}Hi from parent.{% endblock %}
# child.tmpl
{% extends "parent.tmpl" %}
{% block body %}Hi from child. {{ super() }}{% endblock %}
# grandchild1.tmpl
{% extends "child.tmpl" %}
{% block body %}Hi from grandchild1.{% endblock %}
# grandchild2.tmpl
{% extends "child.tmpl" %}
{% block body %}Hi from grandchild2. {{ super.super() }} {% endblock %}
Рендеринг child.tmpl даст body: Hi from child. Hi from parent.
Рендеринг grandchild1.tmpl даст body: Hi from grandchild1.
Рендеринг grandchild2.tmpl даст body: Hi from grandchild2. Hi from parent.
Именованные теги закрытия блока
Jinja позволяет вам помещать имя блока после закрывающего тега для лучшей читаемости:
{% block sidebar %}
{% block inner_sidebar %}
...
{% endblock inner_sidebar %}
{% endblock sidebar %}
Однако имя после слова endblock должно совпадать с именем блока.
Вложенность блоков и область видимости
Блоки могут быть вложенными для более сложных макетов. Однако по умолчанию блоки не могут получать доступ к переменным из внешних областей видимости:
{% for item in seq %}
<li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}
Этот пример выведет пустые элементы <li>, потому что item недоступен внутри блока. Причина этого в том, что если блок заменяется дочерним шаблоном, появится переменная, которая не была определена в блоке или передана в контекст.
Начиная с Jinja 2.2, вы можете явно указать, что переменные доступны в блоке, установив блок как «область видимости», добавив модификатор scoped к объявлению блока:
{% for item in seq %}
<li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}
При переопределении блока модификатор scoped указывать не обязательно.
Объекты шаблонов
Журнал изменений
Изменено в версии 2.4.
Если объект шаблона был передан в контекст шаблона, вы также можете расширить его из этого объекта. Предполагая, что вызывающий код передает шаблон макета как layout_template в среду, этот код работает:
{% extends layout_template %}
Ранее переменная layout_template должна была быть строкой с именем файла шаблона макета, чтобы это работало.
HTML-кодирование
При генерации HTML из шаблонов всегда существует риск, что переменная будет содержать символы, которые влияют на результирующий HTML. Существует два подхода:
- ручное кодирование каждой переменной; или
- автоматическое кодирование всего по умолчанию.
Jinja поддерживает оба варианта. Что используется, зависит от конфигурации приложения. Конфигурация по умолчанию — без автоматического кодирования; по нескольким причинам:
- Кодирование всего, кроме безопасных значений, также будет означать, что Jinja кодирует переменные, которые, как известно, не содержат HTML (например, числа, булевы значения), что может значительно снизить производительность.
- Информация о безопасности переменной очень хрупка. Может случиться так, что при приведении безопасных и небезопасных значений результирующее значение будет представлять собой дважды закодированный HTML.
Работа с ручным кодированием
Если включено ручное кодирование, ваша задача — кодировать переменные, если это необходимо. Что кодировать? Если у вас есть переменная, которая может содержать любой из следующих символов (>, <, & или ") вы ДОЛЖНЫ закодировать её, если только переменная не содержит корректно сформированного и заслуживающего доверия HTML. Кодирование работает путем пропуска переменной через фильтр |e:
{{ user.username|e }}
Работа с автоматическим кодированием
Когда включено автоматическое кодирование, всё кодируется по умолчанию, за исключением значений, явно помеченных как безопасные. Переменные и выражения могут быть помечены как безопасные либо в:
- словаре контекста приложением с помощью
markupsafe.Markup - шаблоне, с помощью фильтра
|safe.
Если строка, которую вы пометили как безопасную, передается через другой код Python, который не понимает эту метку, она может быть потеряна. Обращайте внимание на то, когда ваши данные помечены как безопасные и как они обрабатываются до попадания в шаблон.
Если значение было закодировано, но не помечено как безопасное, автоматическое кодирование все равно будет выполняться и приведет к появлению дважды закодированных символов. Если вы знаете, что у вас есть данные, которые уже безопасны, но не помечены, обязательно оберните их в Markup или используйте фильтр |safe.
Функции Jinja (макросы, super, self.BLOCKNAME) всегда возвращают данные шаблона, помеченные как безопасные.
Строковые литералы в шаблонах с автоматическим кодированием считаются небезопасными, потому что собственные строки Python (str, unicode, basestring) не являются строками MarkupSafe.Markup с атрибутом __html__.
Список управляющих структур
Управляющая структура относится ко всем тем вещам, которые управляют потоком программы — условным операторам (т.е. if/elif/else), циклам for, а также таким вещам, как макросы и блоки. С синтаксисом по умолчанию управляющие структуры отображаются внутри блоков {% ... %}.
For
Перебор каждого элемента в последовательности. Например, для отображения списка пользователей, предоставленного в переменной под названием users:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
Поскольку переменные в шаблонах сохраняют свои свойства объектов, можно перебирать контейнеры, такие как dict:
<dl>
{% for key, value in my_dict.items() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
</dl>
Обратите внимание, однако, что словари Python не упорядочены; поэтому вы можете либо передать отсортированный list из tuple в шаблон, либо использовать фильтр dictsort.
Внутри блока for-цикла можно получить доступ к некоторым специальным переменным:
Переменная | Описание |
|---|---|
| Текущая итерация цикла. (с индексом 1) |
| Текущая итерация цикла. (с индексом 0) |
| Количество итераций от конца цикла (с индексом 1) |
| Количество итераций от конца цикла (с индексом 0) |
| Истина, если первая итерация. |
| Истина, если последняя итерация. |
| Количество элементов в последовательности. |
| Вспомогательная функция для циклического перебора списка последовательностей. См. объяснение ниже. |
| Указывает, насколько глубоко в рекурсивном цикле находится в данный момент рендеринг. Начинается с уровня 1 |
| Указывает, насколько глубоко в рекурсивном цикле находится в данный момент рендеринг. Начинается с уровня 0 |
| Элемент из предыдущей итерации цикла. Не определен во время первой итерации. |
| Элемент из следующей итерации цикла. Не определен во время последней итерации. |
| Истина, если ранее вызывалось с другим значением (или вообще не вызывалось). |
Внутри цикла for можно циклически перебирать список строк/переменных на каждой итерации, используя специальный помощник loop.cycle:
{% for row in rows %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
Начиная с Jinja 2.1, существует дополнительный помощник cycle, который позволяет циклически перебирать без привязки к циклу. Для получения дополнительной информации ознакомьтесь с List of Global Functions.
В отличие от Python, нельзя break или continue в цикле. Однако вы можете фильтровать последовательность во время итерации, что позволяет пропускать элементы. В следующем примере пропускаются все пользователи, которые скрыты:
{% for user in users if not user.hidden %}
<li>{{ user.username|e }}</li>
{% endfor %}
Преимущество заключается в том, что специальная переменная loop будет считаться корректно; таким образом, не считаются пользователи, которые не перебираются.
Если итерация не произошла, потому что последовательность была пустой или фильтрация удалила все элементы из последовательности, вы можете отобразить блок по умолчанию, используя else:
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% else %}
<li><em>no users found</em></li>
{% endfor %}
</ul>
Обратите внимание, что в Python блоки else выполняются всякий раз, когда соответствующий цикл не break. Поскольку циклы Jinja не могут break в любом случае, было выбрано немного другое поведение ключевого слова else.
Также можно использовать циклы рекурсивно. Это полезно, если вы работаете с рекурсивными данными, такими как карты сайта или RDFa. Чтобы использовать циклы рекурсивно, вам в основном нужно добавить модификатор recursive к определению цикла и вызвать переменную loop с новой итерируемой сущностью, где вы хотите выполнить рекурсию.
В следующем примере реализована карта сайта с рекурсивными циклами:
<ul class="sitemap">
{%- for item in sitemap recursive %}
<li><a href="{{ item.href|e }}">{{ item.title }}</a>
{%- if item.children -%}
<ul class="submenu">{{ loop(item.children) }}</ul>
{%- endif %}</li>
{%- endfor %}
</ul>
Переменная loop всегда ссылается на ближайший (внутренний) цикл. Если у нас более одного уровня циклов, мы можем перепривязать переменную loop написав {% set outer_loop = loop %} после цикла, который мы хотим использовать рекурсивно. Затем мы можем вызвать его используя {{ outer_loop(…) }}
Обратите внимание, что присваивания в циклах будут очищены в конце итерации и не могут выходить за пределы области видимости цикла. В более старых версиях Jinja была ошибка, из-за которой в некоторых случаях казалось, что присваивания работают. Это не поддерживается. См. Присваивания для получения дополнительной информации о том, как с этим бороться.
Если все, что вы хотите сделать, это проверить, изменилось ли какое-либо значение с последней итерации или изменится ли оно на следующей итерации, вы можете использовать previtem и nextitem:
{% 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 %}
Если вас интересует только то, изменилось ли значение вообще, использование changed ещё проще:
{% for entry in entries %}
{% if loop.changed(entry.category) %}
<h2>{{ entry.category }}</h2>
{% endif %}
<p>{{ entry.message }}</p>
{% endfor %}
If
Оператор if в Jinja сопоставим с оператором if в Python. В простейшем виде его можно использовать для проверки, определена ли переменная, не пуста и не ложна:
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
Для нескольких ветвей можно использовать elif и else, как в Python. Вы также можете использовать более сложные Выражения:
{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
If также может использоваться как встроенное выражение и для фильтрации цикла.
Макросы
Макросы сопоставимы с функциями в обычных языках программирования. Они полезны для помещения часто используемых идиом в многоразовые функции, чтобы не повторяться («DRY»).
Вот небольшой пример макроса, который отображает элемент формы:
{% macro input(name, value='', type='text', size=20) -%}
<input type="{{ type }}" name="{{ name }}" value="{{
value|e }}" size="{{ size }}">
{%- endmacro %}
Затем макрос можно вызывать как функцию в пространстве имен:
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>
Если макрос был определен в другом шаблоне, вы должны сначала импортировать его.
Внутри макросов у вас есть доступ к трем специальным переменным:
-
varargs -
Если макросу передается больше позиционных аргументов, чем он принимает, они попадают в специальную переменную
varargsв виде списка значений. -
kwargs -
Как
varargs, но для именованных аргументов. Все неиспользованные именованные аргументы хранятся в этой специальной переменной. -
caller -
Если макрос был вызван из тега call, вызывающий хранится в этой переменной как вызываемый макрос.
Макросы также предоставляют некоторые внутренние данные. Следующие атрибуты доступны для объекта макроса:
-
name -
Имя макроса.
{{ input.name }}выведетinput. -
arguments -
Кортеж имен аргументов, которые принимает макрос.
-
defaults -
Кортеж значений по умолчанию.
-
catch_kwargs -
Это
true, если макрос принимает дополнительные именованные аргументы (т.е. обращается к специальной переменнойkwargs). -
catch_varargs -
Это
true, если макрос принимает дополнительные позиционные аргументы (т.е. обращается к специальной переменнойvarargs). -
caller -
Это
true, если макрос обращается к специальной переменнойcallerи может быть вызван из тега call.
Если имя макроса начинается с подчеркивания, он не экспортируется и не может быть импортирован.
Call
В некоторых случаях может быть полезно передать макрос другому макросу. Для этой цели можно использовать специальный блок call. В следующем примере показан макрос, который использует функциональность вызова, и как его можно использовать:
{% macro render_dialog(title, class='dialog') -%}
<div class="{{ class }}">
<h2>{{ title }}</h2>
<div class="contents">
{{ caller() }}
</div>
</div>
{%- endmacro %}
{% call render_dialog('Hello World') %}
This is a simple dialog rendered by using a macro and
a call block.
{% endcall %}
Также можно передавать аргументы обратно в блок call. Это делает его полезным в качестве замены циклов. В общем, блок call работает точно так же, как макрос без имени.
Вот пример того, как блок call можно использовать с аргументами:
{% macro dump_users(users) -%}
<ul>
{%- for user in users %}
<li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
{%- endfor %}
</ul>
{%- endmacro %}
{% call(user) dump_users(list_of_user) %}
<dl>
<dl>Realname</dl>
<dd>{{ user.realname|e }}</dd>
<dl>Description</dl>
<dd>{{ user.description }}</dd>
</dl>
{% endcall %}
Фильтры
Разделы фильтров позволяют применять обычные фильтры Jinja к блоку данных шаблона. Просто заключите код в специальный раздел filter:
{% filter upper %}
This text becomes uppercase
{% endfilter %}
Присваивания
Внутри блоков кода вы также можете присваивать значения переменным. Присваивания на верхнем уровне (вне блоков, макросов или циклов) экспортируются из шаблона как макросы верхнего уровня и могут быть импортированы другими шаблонами.
Присваивания используют тег set и могут иметь несколько целей:
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
Поведение области видимости
Пожалуйста, имейте в виду, что невозможно устанавливать переменные внутри блока и отображать их за его пределами. Это также относится к циклам. Единственным исключением из этого правила являются операторы if, которые не создают область видимости. В результате следующий шаблон не будет делать того, чего вы могли ожидать:
{% set iterated = false %}
{% for item in seq %}
{{ item }}
{% set iterated = true %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %}
С синтаксисом Jinja это невозможно. Вместо этого используйте альтернативные конструкции, такие как блок else цикла или специальная переменная loop:
{% for item in seq %}
{{ item }}
{% else %}
did not iterate
{% endfor %}
Начиная с версии 2.10 более сложные варианты использования могут обрабатываться с помощью объектов пространства имен, которые позволяют распространять изменения по областям видимости:
{% 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 }}
Обратите внимание, что обозначение obj.attr в теге set разрешено только для объектов пространства имен; попытка присвоить атрибут любому другому объекту приведет к исключению.
Журнал изменений
Новое в версии 2.10: Добавлена поддержка объектов пространства имен
Присваивания блоков
Журнал изменений
Новое в версии 2.8.
Начиная с Jinja 2.8, можно также использовать присваивания блоков для сохранения содержимого блока в имя переменной. Это может быть полезно в некоторых ситуациях в качестве альтернативы макросам. В этом случае, вместо использования знака равенства и значения, вы просто пишете имя переменной, а затем все до {% endset %} будет захвачено.
Пример:
{% set navigation %}
<li><a href="/">Index</a>
<li><a href="/downloads">Downloads</a>
{% endset %}
Переменная navigation затем содержит исходный HTML-код навигации.
Журнал изменений
Изменено в версии 2.10.
Начиная с Jinja 2.10, присваивание блока поддерживает фильтры.
Пример:
{% set reply | wordwrap %}
You wrote:
{{ message }}
{% endset %}
Extends
Тег extends может использоваться для расширения одного шаблона из другого. Вы можете иметь несколько тегов extends в файле, но только один из них может быть выполнен за один раз.
См. раздел о Наследовании шаблонов выше.
Блоки
Блоки используются для наследования и одновременно выступают в качестве заполнителей и заменителей. Они подробно описаны в разделе Наследование шаблонов.
Include
Тег include полезен для включения шаблона и возврата отрендеренного содержимого этого файла в текущее пространство имен:
{% include 'header.html' %}
Body
{% include 'footer.html' %}
Включенные шаблоны по умолчанию имеют доступ к переменным активного контекста. Для получения более подробной информации о поведении контекста импорта и включения см. Поведение контекста импорта.
Начиная с Jinja 2.2, вы можете пометить include с ignore missing; в этом случае Jinja проигнорирует инструкцию, если включаемый шаблон не существует. В сочетании с with или without context, он должен быть помещен перед инструкцией видимости контекста. Вот несколько допустимых примеров:
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}
Журнал изменений
Новое в версии 2.2.
Вы также можете предоставить список шаблонов, которые проверяются на существование перед включением. Будет включен первый существующий шаблон. Если указан ignore missing, он вернется к отображению ничего, если ни один из шаблонов не существует, иначе будет вызвано исключение.
Пример:
{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}
Журнал изменений
Изменено в версии 2.4: Если объект шаблона был передан в контекст шаблона, вы можете включить этот объект, используя include.
Import
Jinja поддерживает размещение часто используемого кода в макросах. Эти макросы могут находиться в разных шаблонах и импортироваться оттуда. Это работает аналогично операторам импорта в Python. Важно знать, что импорты кэшируются, и импортированные шаблоны по умолчанию не имеют доступа к текущим переменным шаблона, а только к глобальным. Для получения более подробной информации о поведении контекста импорта и включения см. Поведение контекста импорта.
Существует два способа импорта шаблонов. Вы можете импортировать весь шаблон в переменную или запросить из него определенные макросы / экспортированные переменные.
Представьте, что у нас есть вспомогательный модуль, который отображает формы (называемый forms.html):
{% macro input(name, value='', type='text') -%}
<input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}
{%- macro textarea(name, value='', rows=10, cols=40) -%}
<textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
}}">{{ value|e }}</textarea>
{%- endmacro %}
Самый простой и гибкий способ доступа к переменным и макросам шаблона — импортировать весь модуль шаблона в переменную. Таким образом, вы можете получить доступ к атрибутам:
{% import 'forms.html' as forms %}
<dl>
<dt>Username</dt>
<dd>{{ forms.input('username') }}</dd>
<dt>Password</dt>
<dd>{{ forms.input('password', type='password') }}</dd>
</dl>
<p>{{ forms.textarea('comment') }}</p>
В качестве альтернативы, вы можете импортировать определенные имена из шаблона в текущее пространство имен:
{% from 'forms.html' import input as input_field, textarea %}
<dl>
<dt>Username</dt>
<dd>{{ input_field('username') }}</dd>
<dt>Password</dt>
<dd>{{ input_field('password', type='password') }}</dd>
</dl>
<p>{{ textarea('comment') }}</p>
Макросы и переменные, начинающиеся с одного или нескольких подчеркиваний, являются приватными и не могут быть импортированы.
Журнал изменений
Изменено в версии 2.4: Если объект шаблона был передан в контекст шаблона, вы можете импортировать из этого объекта.
Поведение контекста импорта
По умолчанию включенным шаблонам передается текущий контекст, а импортированным шаблонам — нет. Причина этого в том, что импорты, в отличие от включений, кэшируются; поскольку импорты часто используются просто как модуль, содержащий макросы.
Это поведение можно явно изменить: добавив with context или without context к директиве импорта/включения, текущий контекст может быть передан шаблону, и кэширование автоматически отключается.
Вот два примера:
{% from 'forms.html' import input with context %}
{% include 'header.html' without context %}
Заметка
В Jinja 2.0 контекст, который передавался во включаемый шаблон, не включал переменные, определенные в шаблоне. По сути, это не работало:
{% for box in boxes %}
{% include "render_box.html" %}
{% endfor %}
Включаемый шаблон render_box.html не может получить доступ к box в Jinja 2.0. Начиная с Jinja 2.1, render_box.html может это делать.
Выражения
Jinja позволяет использовать базовые выражения везде. Они работают очень похоже на обычный Python; даже если вы не работаете с Python, вы должны чувствовать себя комфортно с этим.
Литералы
Простейшей формой выражений являются литералы. Литералы — это представления для объектов Python, таких как строки и числа. Существуют следующие литералы:
-
"Hello World" -
Все, что находится между двумя двойными или одинарными кавычками, является строкой. Они полезны, когда вам нужна строка в шаблоне (например, в качестве аргументов для вызовов функций и фильтров или просто для расширения или включения шаблона).
-
42 / 123_456 -
Целые числа — это целые числа без дробной части. Символ «_» можно использовать для разделения групп для повышения читаемости.
-
42.23 / 42.1e2 / 123_456.789 -
Числа с плавающей точкой могут быть записаны с использованием «.» в качестве десятичной запятой. Они также могут быть записаны в научной нотации с прописной или строчной буквой «e», чтобы указать экспоненциальную часть. Символ «_» можно использовать для разделения групп для повышения читаемости, но его нельзя использовать в экспоненциальной части.
-
['list', 'of', 'objects'] -
Все, что находится между двумя квадратными скобками, является списком. Списки полезны для хранения последовательных данных, которые нужно перебирать. Например, вы можете легко создать список ссылок, используя списки и кортежи для (и с) цикла for:
<ul> {% for href, caption in [('index.html', 'Index'), ('about.html', 'About'), ('downloads.html', 'Downloads')] %} <li><a href="{{ href }}">{{ caption }}</a></li> {% endfor %} </ul> -
('tuple', 'of', 'values') -
Кортежи похожи на списки, которые нельзя изменить («неизменяемые»). Если кортеж содержит только один элемент, за ним должен следовать запятая (
('1-tuple',)). Кортежи обычно используются для представления элементов из двух или более элементов. См. пример списка выше для получения дополнительной информации. -
{'dict': 'of', 'key': 'and', 'value': 'pairs'} -
Словарь в Python — это структура, которая объединяет ключи и значения. Ключи должны быть уникальными и всегда иметь ровно одно значение. Словари редко используются в шаблонах; они полезны в некоторых редких случаях, таких как фильтр
xmlattr(). -
true / false -
trueвсегда истинно, аfalseвсегда ложно.
Заметка
Специальные константы true, false и none действительно строчные. Поскольку это вызывало путаницу в прошлом (True раньше расширялся до неопределенной переменной, которая считалась ложной), все три теперь можно также записать с заглавной буквы (True, False и None). Однако для согласованности (все идентификаторы Jinja строчные) следует использовать строчные версии.
Математика
Jinja позволяет вам вычислять значения. Это редко бывает полезно в шаблонах, но существует ради полноты. Поддерживаются следующие операторы:
-
+ -
Складывает два объекта вместе. Обычно объекты представляют собой числа, но если оба являются строками или списками, вы можете объединить их таким образом. Однако это не предпочтительный способ объединения строк! Для объединения строк посмотрите на оператор
~.{{ 1 + 1 }}равно2. -
- -
Вычитает второе число из первого.
{{ 3 - 2 }}равно1. -
/ -
Делит два числа. Результатом будет число с плавающей точкой.
{{ 1 / 2 }}равно{{ 0.5 }}. -
// -
Делит два числа и возвращает усеченный целочисленный результат.
{{ 20 // 7 }}равно2. -
% -
Вычисляет остаток от целочисленного деления.
{{ 11 % 7 }}равно4. -
* -
Умножает левый операнд на правый.
{{ 2 * 2 }}вернет4. Это также можно использовать для многократного повторения строки.{{ '=' * 80 }}выведет полосу из 80 знаков равенства. -
** -
Возводит левый операнд в степень правого операнда.
{{ 2**3 }}вернет8.
Сравнения
-
== -
Сравнивает два объекта на равенство.
-
!= -
Сравнивает два объекта на неравенство.
-
> -
trueесли левая часть больше правой. -
>= -
trueесли левая часть больше или равна правой. -
< -
trueесли левая часть меньше правой. -
<= -
trueесли левая часть меньше или равна правой.
Логика
Для if операторов, for фильтров и if выражений может быть полезно объединять несколько выражений:
-
and -
Возвращает true, если левый и правый операнды истинны.
-
or -
Возвращает true, если левый или правый операнд истинны.
-
not -
Отрицает утверждение (см. ниже).
-
(expr) -
Скобки группируют выражение.
Заметка
Операторы is и in также поддерживают отрицание с помощью инфиксной записи: foo is not bar и foo not in bar вместо not foo is bar и not foo in bar. Все остальные выражения требуют префиксной записи: not (foo and bar).
Другие операторы
Следующие операторы очень полезны, но не подходят ни к одной из двух других категорий:
-
in -
Выполняет проверку на вхождение в последовательность/отображение. Возвращает true, если левый операнд содержится в правом.
{{ 1 in [1, 2, 3] }}, например, вернет true. -
is -
Выполняет тест.
-
| -
Применяет фильтр.
-
~ -
Преобразует все операнды в строки и объединяет их.
{{ "Hello " ~ name ~ "!" }}вернет (предполагая, чтоnameустановлено в'John')Hello John!. -
() -
Вызывает вызываемый объект:
{{ post.render() }}. Внутри скобок вы можете использовать позиционные и именованные аргументы, как в Python:{{ post.render(user, full=true) }}. -
. / [] -
Получает атрибут объекта. (См. Переменные)
Условное выражение
Также можно использовать встроенные if выражения. Они полезны в некоторых ситуациях. Например, вы можете использовать это для расширения из одного шаблона, если переменная определена, иначе из шаблона макета по умолчанию:
{% extends layout_template if layout_template is defined else 'master.html' %}
Общий синтаксис: <do something> if <something is true> else <do
something else>.
Часть else является необязательной. Если она не указана, блок else неявно вычисляется в объект Undefined (независимо от того, что установлено в undefined в среде):
{{ "[{}]".format(page.title) if page.title }}
Методы Python
Вы также можете использовать любые методы, определенные для типа переменной. Значение, возвращаемое из вызова метода, используется как значение выражения. Вот пример, который использует методы, определенные для строк (где page.title — это строка):
{{ page.title.capitalize() }}
Это работает для методов для пользовательских типов. Например, если переменная f типа Foo имеет метод bar, определенный для нее, вы можете сделать следующее:
{{ f.bar(value) }}
Операторные методы также работают как ожидалось. Например, % реализует printf-стиль для строк:
{{ "Hello, %s!" % name }}
Хотя в этом случае следует предпочесть метод .format (который немного надуман в контексте отрисовки шаблона):
{{ "Hello, {}!".format(name) }}
Список встроенных фильтров
-
abs(x, /) -
Возвращает абсолютное значение аргумента.
-
attr(obj, name) -
Получает атрибут объекта.
foo|attr("bar")работает так же, какfoo.bar, за исключением того, что всегда возвращается атрибут, и элементы не ищутся.См. Примечания по подпискам для получения дополнительной информации.
-
batch(value, linecount, fill_with=None) -
Фильтр, группирующий элементы. Он работает почти так же, как
slice, только наоборот. Он возвращает список списков с заданным количеством элементов. Если вы предоставите второй параметр, он будет использоваться для заполнения недостающих элементов. См. этот пример:<table> {%- for row in items|batch(3, ' ') %} <tr> {%- for column in row %} <td>{{ column }}</td> {%- endfor %} </tr> {%- endfor %} </table>
-
capitalize(s) -
Преобразует значение в заглавный регистр. Первый символ будет заглавным, все остальные — строчными.
-
center(value, width=80) -
Выравнивает значение по центру в поле заданной ширины.
-
default(value, default_value='', boolean=False) -
Если значение не определено, он вернет переданное значение по умолчанию, иначе значение переменной:
{{ my_variable|default('my_variable is not defined') }}Это выведет значение
my_variable, если переменная была определена, иначе'my_variable is not defined'. Если вы хотите использовать значение по умолчанию с переменными, которые вычисляются как false, вы должны установить второй параметр вtrue:{{ ''|default('the string was empty', true) }}Изменено в версии 2.11: Теперь можно настроить
Environmentс помощьюChainableUndefined, чтобы фильтрdefaultработал с вложенными элементами и атрибутами, которые могут содержать неопределенные значения в цепочке, не вызываяUndefinedError.- Псевдонимы
-
d
-
dictsort(value, case_sensitive=False, by='key', reverse=False) -
Сортирует словарь и выдает пары (ключ, значение). Поскольку словари Python не отсортированы, вы можете использовать эту функцию для их упорядочивания по ключу или значению:
{% for item in mydict|dictsort %} sort the dict by key, case insensitive {% for item in mydict|dictsort(reverse=true) %} sort the dict by key, case insensitive, reverse order {% for item in mydict|dictsort(true) %} sort the dict by key, case sensitive {% for item in mydict|dictsort(false, 'value') %} sort the dict by value, case insensitive
-
escape(s) -
Преобразует символы &, <, >, ‘ и ” в строке s в безопасные для HTML последовательности. Используйте это, если вам нужно отобразить текст, который может содержать такие символы в HTML. Отмечает возвращаемое значение как строку разметки.
- Псевдонимы
-
e
-
filesizeformat(value, binary=False) -
Форматирует значение как «читаемый человеком» размер файла (например, 13 kB, 4.1 MB, 102 байта и т. д.). По умолчанию используются десятичные префиксы (Мега, Гига и т. д.), если второй параметр установлен в
True, используются двоичные префиксы (Меби, Гиби).
-
first(seq) -
Возвращает первый элемент последовательности.
-
float(value, default=0.0) -
Преобразует значение в число с плавающей точкой. Если преобразование не работает, он вернет
0.0. Вы можете переопределить это значение по умолчанию, используя первый параметр.
-
forceescape(value) -
Принудительное экранирование HTML. Это, вероятно, приведет к двойному экранированию переменных.
-
format(value, *args, **kwargs) -
Применяет заданные значения к строке форматирования в стиле printf, например
string % values.{{ "%s, %s!"|format(greeting, name) }} Hello, World!В большинстве случаев удобнее и эффективнее использовать оператор
%илиstr.format().{{ "%s, %s!" % (greeting, name) }} {{ "{}, {}!".format(greeting, name) }}
-
groupby(value, attribute) -
Группирует последовательность объектов по атрибуту, используя
itertools.groupby()Python. Атрибут может использовать точечную нотацию для вложенного доступа, например"address.city". В отличие отgroupbyPython, значения сначала сортируются, поэтому для каждого уникального значения возвращается только одна группа.Например, список объектов
Userс атрибутомcityможет быть отображен группами. В этом примереgrouperотносится к значениюcityгруппы.<ul>{% for city, items in users|groupby("city") %} <li>{{ city }} <ul>{% for user in items %} <li>{{ user.name }} {% endfor %}</ul> </li> {% endfor %}</ul>groupbyвозвращает именованные кортежи(grouper, list), которые могут быть использованы вместо распаковки кортежа выше.grouper— это значение атрибута, аlist— это элементы с этим значением.<ul>{% for group in users|groupby("city") %} <li>{{ group.grouper }}: {{ group.list|join(", ") }} {% endfor %}</ul>Журнал изменений
Изменено в версии 2.6: Атрибут поддерживает точечную нотацию для вложенного доступа.
-
indent(s, width=4, first=False, blank=False, indentfirst=None) -
Возвращает копию строки с каждой строкой, отступом в 4 пробела. Первая строка и пустые строки по умолчанию не имеют отступа.
- Параметры
-
- width – Количество пробелов для отступа.
- first – Не пропускать отступ первой строки.
- blank – Не пропускать отступ пустых строк.
Журнал изменений
Изменено в версии 2.10: Пустые строки по умолчанию не имеют отступа.
Переименован аргумент
indentfirstвfirst.
-
int(value, default=0, base=10) -
Преобразует значение в целое число. Если преобразование не удается, возвращается
0. Вы можете переопределить это значение по умолчанию, используя первый параметр. Вы также можете переопределить основание по умолчанию (10) во втором параметре, который обрабатывает входные данные с префиксами, такими как 0b, 0o и 0x для оснований 2, 8 и 16 соответственно. Основание игнорируется для десятичных чисел и значений, не являющихся строками.
-
join(value, d='', attribute=None) -
Возвращает строку, которая является конкатенацией строк в последовательности. Разделитель между элементами по умолчанию является пустой строкой, вы можете определить его с помощью дополнительного параметра:
{{ [1, 2, 3]|join('|') }} -> 1|2|3 {{ [1, 2, 3]|join }} -> 123Также можно объединять определенные атрибуты объекта:
{{ users|join(', ', attribute='username') }}Журнал изменений
Новое в версии 2.6: Был добавлен параметр
attribute.
-
last(seq) -
Возвращает последний элемент последовательности.
Примечание: Не работает с генераторами. Возможно, потребуется явно преобразовать его в список:
{{ data | selectattr('name', '==', 'Jinja') | list | last }}
-
length(obj, /) -
Возвращает количество элементов в контейнере.
- Псевдонимы
-
count
-
list(value) -
Преобразует значение в список. Если это была строка, возвращаемый список будет списком символов.
-
lower(s) -
Преобразует значение в нижний регистр.
-
map(*args, **kwargs) -
Применяет фильтр к последовательности объектов или ищет атрибут. Это полезно при работе со списками объектов, но вы действительно заинтересованы только в определенном значении.
Основное использование — сопоставление по атрибуту. Представьте, что у вас есть список пользователей, но вас интересует только список имен пользователей:
Users on this page: {{ users|map(attribute='username')|join(', ') }}Вы можете указать значение
default, которое будет использоваться, если объект в списке не имеет данного атрибута.{{ users|map(attribute="username", default="Anonymous")|join(", ") }}В качестве альтернативы вы можете позволить ему вызывать фильтр, передав имя фильтра и аргументы после него. Хорошим примером будет применение фильтра преобразования текста к последовательности:
Users on this page: {{ titles|map('lower')|join(', ') }}Аналогично генераторному выражению, такому как:
(u.username for u in users) (u.username or "Anonymous" for u in users) (do_lower(x) for x in titles)
Изменено в версии 2.11.0: Добавлен параметр
default.Журнал изменений
Новое в версии 2.7.
-
max(value, case_sensitive=False, attribute=None) -
Возвращает наибольший элемент из последовательности.
{{ [1, 2, 3]|max }} -> 3- Параметры
-
- case_sensitive – Рассматривать строки верхнего и нижнего регистра как различные.
- attribute – Получить объект с максимальным значением этого атрибута.
-
min(value, case_sensitive=False, attribute=None) -
Возвращает наименьший элемент из последовательности.
{{ [1, 2, 3]|min }} -> 1- Параметры
-
- case_sensitive – Рассматривать строки верхнего и нижнего регистра как различные.
- attribute – Получить объект с минимальным значением этого атрибута.
-
pprint(value, verbose=False) -
Красивая печать переменной. Полезно для отладки.
Начиная с Jinja 1.2, вы можете передать ему параметр. Если этот параметр истинно, вывод будет более подробным (для этого требуется
pretty)
-
random(seq) -
Возвращает случайный элемент из последовательности.
-
reject(*args, **kwargs) -
Фильтрует последовательность объектов, применяя тест к каждому объекту и отклоняя объекты, для которых тест успешен.
Если тест не указан, каждый объект будет оцениваться как булево значение.
Пример использования:
{{ numbers|reject("odd") }}Аналогично генераторному выражению, такому как:
(n for n in numbers if not test_odd(n))
Журнал изменений
Новое в версии 2.7.
-
rejectattr(*args, **kwargs) -
Фильтрует последовательность объектов, применяя тест к указанному атрибуту каждого объекта и отклоняя объекты, для которых тест успешен.
Если тест не указан, значение атрибута будет оцениваться как булево значение.
{{ users|rejectattr("is_active") }} {{ users|rejectattr("email", "none") }}Аналогично генераторному выражению, такому как:
(u for user in users if not user.is_active) (u for user in users if not test_none(user.email))
Журнал изменений
Новое в версии 2.7.
-
replace(s, old, new, count=None) -
Возвращает копию значения со всеми вхождениями подстроки, замененными на новую. Первый аргумент — подстрока, которая должна быть заменена, второй — строка замены. Если задан дополнительный третий аргумент
count, заменяются только первыеcountвхождения:{{ "Hello World"|replace("Hello", "Goodbye") }} -> Goodbye World {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} -> d'oh, d'oh, aaargh
-
reverse(value) -
Разворачивает объект или возвращает итератор, который итерируется по нему в обратном порядке.
-
round(value, precision=0, method='common') -
Округляет число до заданной точности. Первый параметр указывает точность (по умолчанию
0), второй — метод округления:-
'common'округляет вверх или вниз -
'ceil'всегда округляет вверх -
'floor'всегда округляет вниз
Если вы не указываете метод, используется
'common'.{{ 42.55|round }} -> 43.0 {{ 42.55|round(1, 'floor') }} -> 42.5Обратите внимание, что даже если округлено до 0 знаков после запятой, возвращается число с плавающей запятой. Если вам нужно целое число, передайте его через %%%CODE_BLOCK_493%%:
{{ 42.55|round|int }} -> 43 -
-
safe(value) -
Помечает значение как безопасное, что означает, что в среде с включенным автоматическим экранированием эта переменная не будет экранироваться.
-
select(*args, **kwargs) -
Фильтрует последовательность объектов, применяя тест к каждому объекту и выбирая только объекты, для которых тест успешен.
Если тест не указан, каждый объект будет оцениваться как булево значение.
Пример использования:
{{ numbers|select("odd") }} {{ numbers|select("odd") }} {{ numbers|select("divisibleby", 3) }} {{ numbers|select("lessthan", 42) }} {{ strings|select("equalto", "mystring") }}Аналогично генераторному выражению, такому как:
(n for n in numbers if test_odd(n)) (n for n in numbers if test_divisibleby(n, 3))
Журнал изменений
Новое в версии 2.7.
-
selectattr(*args, **kwargs) -
Фильтрует последовательность объектов, применяя тест к указанному атрибуту каждого объекта и выбирая только объекты, для которых тест успешен.
Если тест не указан, значение атрибута будет оцениваться как булево значение.
Пример использования:
{{ users|selectattr("is_active") }} {{ users|selectattr("email", "none") }}Аналогично генераторному выражению, такому как:
(u for user in users if user.is_active) (u for user in users if test_none(user.email))
Журнал изменений
Новое в версии 2.7.
-
slice(value, slices, fill_with=None) -
Разрезает итератор и возвращает список списков, содержащих эти элементы. Полезно, если вы хотите создать div, содержащий три тега ul, которые представляют столбцы:
<div class="columnwrapper"> {%- for column in items|slice(3) %} <ul class="column-{{ loop.index }}"> {%- for item in column %} <li>{{ item }}</li> {%- endfor %} </ul> {%- endfor %} </div>Если вы передадите ему второй аргумент, он будет использоваться для заполнения недостающих значений на последней итерации.
-
sort(value, reverse=False, case_sensitive=False, attribute=None) -
Сортирует итерируемый объект, используя функцию Python
sorted().{% for city in cities|sort %} ... {% endfor %}- Параметры
-
- reverse – Сортировать по убыванию вместо по возрастанию.
- case_sensitive – При сортировке строк сортировать верхний и нижний регистр отдельно.
-
attribute – При сортировке объектов или словарей — атрибут или ключ для сортировки. Можно использовать точечную нотацию, например
"address.city". Может быть списком атрибутов, например"age,name".
Сортировка стабильна, она не изменяет относительный порядок элементов, которые сравниваются как равные. Это позволяет объединять сортировки по различным атрибутам и порядку.
{% for user in users|sort(attribute="name") |sort(reverse=true, attribute="age") %} ... {% endfor %}В качестве сокращения для объединения, когда направление одинаково для всех атрибутов, передайте список атрибутов, разделенных запятыми.
{% for user users|sort(attribute="age,name") %} ... {% endfor %}Изменено в версии 2.11.0: Параметр
attributeможет быть списком атрибутов, разделенных запятыми, например"age,name".Журнал изменений
Изменено в версии 2.6: Был добавлен параметр
attribute.
-
string(object) -
Делает строку unicode, если она ещё не является таковой. Таким образом, строка разметки не будет преобразована обратно в unicode.
-
Удаляет теги SGML/XML и заменяет смежные пробелы одним пробелом.
-
sum(iterable, attribute=None, start=0) -
Возвращает сумму последовательности чисел плюс значение параметра ‘start’ (по умолчанию 0). Когда последовательность пуста, возвращает start.
Также можно суммировать только определенные атрибуты:
Total: {{ items|sum(attribute='price') }}Журнал изменений
Изменено в версии 2.6: Был добавлен параметр
attributeдля суммирования по атрибутам. Также параметрstartбыл перемещен вправо.
-
title(s) -
Возвращает версию значения с заглавными буквами. То есть слова будут начинаться с заглавных букв, все остальные символы — строчные.
-
tojson(value, indent=None) -
Преобразует структуру в JSON, чтобы её можно было безопасно использовать в тегах
<script>. Принимает те же аргументы и возвращает строку JSON. Обратите внимание, что это доступно в шаблонах через фильтр|tojson, который также пометит результат как безопасный. Из-за того, как эта функция экранирует определённые символы, это безопасно даже при использовании за пределами тегов<script>.В строках экранируются следующие символы:
<>&'
Это делает безопасным встраивание таких строк в любое место в HTML, за заметным исключением атрибутов в двойных кавычках. В этом случае используйте одинарные кавычки для атрибутов или дополнительно экранируйте их в HTML.
Параметр indent можно использовать для включения форматирования. Установите его в количество пробелов, с которыми должны быть отступы структур.
Обратите внимание, что этот фильтр предназначен только для использования в контексте HTML.
Журнал изменений
Новое в версии 2.9.
-
trim(value, chars=None) -
Удаляет начальные и конечные символы, по умолчанию пробельные символы.
-
truncate(s, length=255, killwords=False, end='...', leeway=None) -
Возвращает усечённую копию строки. Длина указывается первым параметром, который по умолчанию равен
255. Если второй параметр равенtrue, фильтр обрежет текст до указанной длины. В противном случае он отбросит последнее слово. Если текст был действительно усечён, к нему будет добавлен знак многоточия ("..."). Если вы хотите использовать другой знак многоточия, чем"...", вы можете указать его, используя третий параметр. Строки, которые превышают длину только на допустимый запас, указанный в четвёртом параметре, усекаться не будут.{{ "foo bar baz qux"|truncate(9) }} -> "foo..." {{ "foo bar baz qux"|truncate(9, True) }} -> "foo ba..." {{ "foo bar baz qux"|truncate(11) }} -> "foo bar baz qux" {{ "foo bar baz qux"|truncate(11, False, '...', 0) }} -> "foo bar..."Допустимый запас по умолчанию в новых версиях Jinja равен 5 и был 0 ранее, но может быть переконфигурирован глобально.
-
unique(value, case_sensitive=False, attribute=None) -
Возвращает список уникальных элементов из заданной итерируемой последовательности.
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }} -> ['foo', 'bar', 'foobar']Уникальные элементы возвращаются в том же порядке, что и их первое вхождение в итерируемую последовательность, переданную в фильтр.
- Параметры
-
- case_sensitive – Рассматривать строки в верхнем и нижнем регистре как различные.
- attribute – Фильтровать объекты с уникальными значениями для этого атрибута.
-
upper(s) -
Преобразует значение в верхний регистр.
-
urlencode(value) -
Кодирует данные для использования в пути или запросе URL с использованием UTF-8.
Базовый обёртку вокруг
urllib.parse.quote()при передаче строки илиurllib.parse.urlencode()для словаря или итерируемой последовательности.- Параметры
-
value – Данные для кодирования. Строка будет закодирована напрямую. Словарь или итерируемая последовательность пар
(key, value)будет соединена как строка запроса.
При передаче строки «/» не кодируется. HTTP-серверы обрабатывают «/» и «%2F» эквивалентно в путях. Если вам нужны кодированные слэши, используйте фильтр
|replace("/", "%2F").Журнал изменений
Новое в версии 2.7.
-
urlize(value, trim_url_limit=None, nofollow=False, target=None, rel=None) -
Преобразует URL-адреса в обычном тексте в кликабельные ссылки.
Если вы передадите фильтру дополнительное целое число, он сократит URL-адреса до этого числа. Также существует третий аргумент, который делает URL-адреса «nofollow»:
{{ mytext|urlize(40, true) }} links are shortened to 40 chars and defined with rel="nofollow"Если указан target, атрибут
targetбудет добавлен к тегу<a>:{{ mytext|urlize(40, target='_blank') }}Журнал изменений
Изменено в версии 2.8+: Добавлен параметр target.
-
wordcount(s) -
Подсчитывает слова в строке.
-
wordwrap(s, width=79, break_long_words=True, wrapstring=None, break_on_hyphens=True) -
Разбивает строку на строки заданной ширины. Существующие символы перевода строки обрабатываются как абзацы, которые разбиваются отдельно.
- Параметры
-
- s – Исходный текст для переноса.
- width – Максимальная длина обернутых строк.
-
break_long_words – Если слово длиннее, чем
width, разбить его на строки. - break_on_hyphens – Если слово содержит дефисы, его можно разбить на строки.
-
wrapstring – Строка для соединения каждой обернутой строки. По умолчанию
Environment.newline_sequence.
Изменено в версии 2.11: Существующие символы перевода строки обрабатываются как абзацы, которые разбиваются отдельно.
Изменено в версии 2.11: Добавлен параметр
break_on_hyphens.Журнал изменений
Изменено в версии 2.7: Добавлен параметр
wrapstring.
-
xmlattr(d, autospace=True) -
Создаёт строку атрибутов SGML/XML на основе элементов в словаре. Все значения, которые не являются ни
none, ниundefined, автоматически экранируются:<ul{{ {'class': 'my_list', 'missing': none, 'id': 'list-%d'|format(variable)}|xmlattr }}> ... </ul>Результат выглядит примерно так:
<ul class="my_list" id="list-42"> ... </ul>
Как вы можете видеть, он автоматически добавляет пробел перед элементом, если фильтр что-то вернул, если только второй параметр не равен false.
Список встроенных тестов
-
boolean(value) -
Возвращает true, если объект является булевым значением.
Новое в версии 2.11.
-
callable(obj, /) -
Возвращает, является ли объект вызываемым (т.е. некоторым типом функции).
Обратите внимание, что классы вызываемы, как и экземпляры классов с методом __call__().
-
defined(value) -
Возвращает true, если переменная определена:
{% if variable is defined %} value of variable: {{ variable }} {% else %} variable is not defined {% endif %}См. фильтр
default()для простого способа установки неопределённых переменных.
-
divisibleby(value, num) -
Проверяет, делится ли переменная на число.
-
eq(a, b, /) -
То же самое, что a == b.
- Псевдонимы
-
==,equalto
-
escaped(value) -
Проверяет, экранировано ли значение.
-
even(value) -
Возвращает true, если переменная чётная.
-
false(value) -
Возвращает true, если объект равен False.
Новое в версии 2.11.
-
float(value) -
Возвращает true, если объект является числом с плавающей точкой.
Новое в версии 2.11.
-
ge(a, b, /) -
То же самое, что a >= b.
- Псевдонимы
-
>=
-
gt(a, b, /) -
То же самое, что a > b.
- Псевдонимы
-
>,greaterthan
-
in(value, seq) -
Проверить, есть ли значение в seq.
Журнал изменений
Новое в версии 2.10.
-
integer(value) -
Возвращает true, если объект является целым числом.
Новое в версии 2.11.
-
iterable(value) -
Проверить, можно ли выполнить итерацию по объекту.
-
le(a, b, /) -
То же самое, что a <= b.
- Псевдонимы
-
<=
-
lower(value) -
Возвращает true, если переменная в нижнем регистре.
-
lt(a, b, /) -
То же самое, что a < b.
- Псевдонимы
-
<,lessthan
-
mapping(value) -
Возвращает true, если объект является отображением (dict и т. д.).
Журнал изменений
Новое в версии 2.6.
-
ne(a, b, /) -
То же самое, что a != b.
- Псевдонимы
-
!=
-
none(value) -
Возвращает true, если переменная равна None.
-
number(value) -
Возвращает true, если переменная является числом.
-
odd(value) -
Возвращает true, если переменная нечетная.
-
sameas(value, other) -
Проверить, указывает ли объект на тот же адрес памяти, что и другой объект:
{% if foo.attribute is sameas false %} the foo attribute really is the `False` singleton {% endif %}
-
sequence(value) -
Возвращает true, если переменная является последовательностью. Последовательности — это переменные, по которым можно выполнить итерацию.
-
string(value) -
Возвращает true, если объект является строкой.
-
true(value) -
Возвращает true, если объект равен True.
Новое в версии 2.11.
-
undefined(value) -
Как
defined(), но наоборот.
-
upper(value) -
Возвращает true, если переменная в верхнем регистре.
Список глобальных функций
Следующие функции доступны в глобальной области видимости по умолчанию:
-
range([start, ]stop[, step]) -
Возвращает список, содержащий арифметическую прогрессию целых чисел.
range(i, j)возвращает[i, i+1, i+2, ..., j-1]; start (!) по умолчанию0. Если указан step, он задает приращение (или уменьшение). Например,range(4)иrange(0, 4, 1)возвращают[0, 1, 2, 3]. Конечная точка опускается! Это точно допустимые индексы для списка из 4 элементов.Это полезно для многократного повторения блока шаблона, например, для заполнения списка. Представьте, что у вас есть 7 пользователей в списке, но вы хотите отобразить три пустых элемента, чтобы обеспечить высоту с помощью CSS:
<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(n=5, html=True, min=20, max=100) -
Генерирует некоторый текст lorem ipsum для шаблона. По умолчанию генерируются пять абзацев HTML, каждый из которых содержит от 20 до 100 слов. Если html равно False, возвращается обычный текст. Это полезно для генерации простого содержимого для тестирования макета.
-
dict(**items) -
Удобная альтернатива литералам dict.
{'foo': 'bar'}то же самое, чтоdict(foo='bar').
-
class cycler(*items) -
Циклически перебирает значения, возвращая их по одному, а затем перезапускаясь после достижения конца.
Аналогично
loop.cycle, но может использоваться за пределами циклов или в нескольких циклах. Например, отобразить список папок и файлов в списке, поочередно присваивая им классы «odd» и «even».{% set row_class = cycler("odd", "even") %} <ul class="browser"> {% for folder in folders %} <li class="folder {{ row_class.next() }}">{{ folder }} {% endfor %} {% for file in files %} <li class="file {{ row_class.next() }}">{{ file }} {% endfor %} </ul>- Параметры
-
items – Каждый позиционный аргумент будет возвращен в заданном порядке для каждого цикла.
Журнал изменений
Новое в версии 2.1.
-
property current -
Возвращает текущий элемент. Эквивалентно элементу, который будет возвращен в следующий раз при вызове
next().
-
next() -
Возвращает текущий элемент, затем переходит к следующему элементу
current.
-
reset() -
Сбрасывает текущий элемент на первый элемент.
-
class joiner(sep=', ') -
Небольшой помощник, который можно использовать для «соединения» нескольких разделов. К джойнеру передается строка, и он будет возвращать эту строку каждый раз, когда он вызывается, за исключением первого раза (в этом случае он возвращает пустую строку). Вы можете использовать это для соединения вещей:
{% set pipe = joiner("|") %} {% if categories %} {{ pipe() }} Categories: {{ categories|join(", ") }} {% endif %} {% if author %} {{ pipe() }} Author: {{ author() }} {% endif %} {% if can_edit %} {{ pipe() }} <a href="?action=edit">Edit</a> {% endif %}Журнал изменений
Новое в версии 2.1.
-
class namespace(...) -
Создает новый контейнер, который позволяет назначение атрибутов с помощью тега
{% set %}:{% set ns = namespace() %} {% set ns.foo = 'bar' %}Основное назначение этого — разрешить передачу значения из тела цикла во внешнюю область видимости. Начальные значения могут быть предоставлены в виде словаря, в виде именованных аргументов или и то, и другое (то же поведение, что и у конструктора Python
dict):{% 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 }}Журнал изменений
Новое в версии 2.10.
Расширения
В следующих разделах рассматриваются встроенные расширения Jinja, которые могут быть включены приложением. Приложение также может предоставлять дополнительные расширения, не охватываемые данной документацией; в этом случае должен существовать отдельный документ, объясняющий эти расширения.
i18n
Если включено расширение i18n, можно пометить текст в шаблоне как подлежащий переводу. Чтобы пометить раздел как подлежащий переводу, используйте блок trans:
{% trans %}Hello, {{ user }}!{% endtrans %}
Внутри блока недопустимы операторы, только текст и простые теги переменных.
Теги переменных могут быть только именем, а не доступом к атрибутам, фильтрами или другими выражениями. Чтобы использовать выражение, привяжите его к имени в теге trans для использования в блоке.
{% trans user=user.username %}Hello, {{ user }}!{% endtrans %}
Чтобы привязать более одного выражения, разделите каждое запятой (,).
{% trans book_title=book.title, author=author.name %}
This is {{ book_title }} by {{ author }}
{% endtrans %}
Для образования множественного числа укажите как единственное, так и множественное число, разделенные тегом pluralize.
{% trans count=list|length %}
There is {{ count }} {{ name }} object.
{% pluralize %}
There are {{ count }} {{ name }} objects.
{% endtrans %}
По умолчанию первая переменная в блоке используется для определения того, использовать ли единственное или множественное число. Если это неверно, укажите переменную, используемую для образования множественного числа, в качестве параметра для pluralize.
{% trans ..., user_count=users|length %}...
{% pluralize user_count %}...{% endtrans %}
При переводе текстовых блоков пробелы и разрывы строк приводят к трудночитаемым и подверженным ошибкам строкам перевода. Чтобы избежать этого, блок trans можно пометить как обрезанный, что заменит все разрывы строк и окружающие их пробелы одним пробелом и удалит ведущие и завершающие пробелы.
{% trans trimmed book_title=book.title %}
This is {{ book_title }}.
You should read it!
{% endtrans %}
Это приводит к This is %(book_title)s. You should read it! в файле перевода.
Если обрезка включена глобально, модификатор notrimmed можно использовать для отключения его для блока.
Журнал изменений
Новое в версии 2.10: Добавлены модификаторы trimmed и notrimmed.
Можно переводить строки в выражениях с помощью этих функций:
-
gettext: перевести одну строку -
ngettext: перевести строку с образованием множественного числа -
_: псевдоним дляgettext
Вы можете вывести переведенную строку следующим образом:
{{ _("Hello, World!") }}
Чтобы использовать заполнители, используйте фильтр format.
{{ _("Hello, %(user)s!")|format(user=user.username) }}
Всегда используйте именованные аргументы для format, так как другие языки могут не использовать слова в том же порядке.
Если активированы вызовы New Style Gettext, использование заполнителей становится проще. Форматирование является частью вызова gettext, а не использования фильтра format.
{{ gettext('Hello World!') }}
{{ gettext('Hello %(name)s!', name='World') }}
{{ ngettext('%(num)d apple', '%(num)d apples', apples|count) }}
Строка форматирования функции ngettext автоматически получает count как параметр num в дополнение к заданным параметрам.
Выражение
Если загружено расширение выражения, доступен тег do, который работает точно так же, как обычное выражение переменной ({{ ... }}); за исключением того, что он ничего не выводит. Это можно использовать для изменения списков:
{% do navigation.append('a string') %}
Управление циклами
Если приложение включает управление циклами, можно использовать break и continue в циклах. Когда достигается break, цикл завершается; если достигается continue, обработка прекращается и продолжается со следующей итерации.
Вот цикл, который пропускает каждый второй элемент:
{% for user in users %}
{%- if loop.index is even %}{% continue %}{% endif %}
...
{% endfor %}
Аналогично, цикл, который прекращает обработку после 10-й итерации:
{% for user in users %}
{%- if loop.index >= 10 %}{% break %}{% endif %}
{%- endfor %}
Обратите внимание, что loop.index начинается с 1, а loop.index0 начинается с 0 (См.: For).
Отладка
Если включено расширение Debug Extension, будет доступен тег {% debug %} для вывода текущего контекста, а также доступных фильтров и тестов. Это полезно для того, чтобы увидеть, что доступно для использования в шаблоне, без настройки отладчика.
<pre>{% debug %}</pre>
{'context': {'cycler': <class 'jinja2.utils.Cycler'>,
...,
'namespace': <class 'jinja2.utils.Namespace'>},
'filters': ['abs', 'attr', 'batch', 'capitalize', 'center', 'count', 'd',
..., 'urlencode', 'urlize', 'wordcount', 'wordwrap', 'xmlattr'],
'tests': ['!=', '<', '<=', '==', '>', '>=', 'callable', 'defined',
..., 'odd', 'sameas', 'sequence', 'string', 'undefined', 'upper']}
Оператор With
Журнал изменений
Новое в версии 2.3.
Оператор with позволяет создавать новую внутреннюю область видимости. Переменные, установленные в этой области видимости, не видны за её пределами.
With вкратце:
{% with %}
{% set foo = 42 %}
{{ foo }} foo is 42 here
{% endwith %}
foo is not visible here any longer
Поскольку часто переменные устанавливаются в начале области видимости, вы можете сделать это в операторе 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) требовалось включить эту функцию с помощью расширения. Теперь она включена по умолчанию.
Переопределение автоматического экранирования
Журнал изменений
Новое в версии 2.4.
При желании вы можете активировать и деактивировать автоматическое экранирование изнутри шаблонов.
Пример:
{% autoescape true %}
Autoescaping is active within this block
{% endautoescape %}
{% autoescape false %}
Autoescaping is inactive within this block
{% endautoescape %}
После endautoescape поведение возвращается к тому, которое было до этого.
Расширение
В старых версиях Jinja (до 2.9) требовалось включить эту функцию с помощью расширения. Теперь она включена по умолчанию.
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://jinja.palletsprojects.com/en/2.11.x/templates/