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

Jinja2 - движок шаблонов для Python

Модуль Jinja2 - это современный и удобный язык шаблонов для Python, созданный по образцу шаблонов Django. Он быстр, т.к. компилируется в код Python, широко используется и безопасен благодаря дополнительной среде выполнения изолированных шаблонов:

Преимущества языка шаблонов Jinja2:

  • Автоматическая система экранирования HTML для предотвращения XSS.
  • Наследование шаблонов, поддержка макросов.
  • Шаблоны компилируются до оптимального кода Python (можно отключить при отладке).
  • При отладке, номера строк исключений точно указывают на неправильную строку в шаблоне.
  • Настраиваемый синтаксис, много встроенный фильтров.
  • Поддержка использования методов стандартных типов Python в шаблонах.
  • Возможность вызова функций Python в шаблонах.

Установка модуля Jinja2 в виртуальное окружение:

# создаем виртуальное окружение, если нет
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# ставим модуль Jinja2
(VirtualEnv):~$ python -m pip install -U Jinja2

Инициализация движка шаблонов Jinja2 в Python.

Модуль Jinja использует центральный объект, называемый средой или окружением jinja2.Environment(). Экземпляры этого класса используются для хранения конфигурации и глобальных объектов, а также для загрузки шаблонов из файловой системы или других мест. Даже если создавать шаблоны из строк с помощью конструктора класса jinja2.Template(), среда Environment создается автоматически, только она будет совместно используемая.

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

Самый простой способ настроить Jinja для загрузки шаблонов для приложения выглядит примерно так:

from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
    loader=PackageLoader('yourapplication', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)

Это создаст шаблонную среду с настройками по умолчанию и загрузчиком loader, который будет искать шаблоны в папке шаблонов templates внутри пакета python yourapplication. Доступны разные загрузчики, также можно написать свой собственный, если необходимо загружать шаблоны из базы данных или других ресурсов. Код примера, так же, определяет автоматическое экранирование файлов с расширениями .html и .xml.

Чтобы загрузить шаблон из среды env, которая определены в примере выше, нужно просто вызвать метод env.get_template(), который затем возвращает загруженный шаблон Template:

template = env.get_template('mytemplate.html')

Чтобы отобразить его с некоторыми переменными, просто вызовите метод Template.render():

print(template.render(the='variables', go='here'))

Использование загрузчика шаблонов вместо передачи обычных строк в Template или Environment.from_string() имеет несколько преимуществ. Помимо того, что загрузчик намного проще в использовании, он также позволяет наследование шаблонов.

Примечания по автоэкранированию.

В будущих версиях Jinja, автоматическое экранирование будет включено по умолчанию из соображений безопасности. Рекомендуется явно настроить автоматическое экранирование, а не полагаться на значение по умолчанию.

Примечания по идентификаторам в шаблонах.

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

Фильтры ищутся в отдельных пространствах имен и имеют слегка измененный синтаксис идентификатора. Фильтры могут содержать точки для группировки по темам. Например, вполне допустимо добавить метод в фильтр и вызвать его как .unicode. Регулярное выражение для проверки идентификаторов фильтров: [a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*.

Базовое использование движка шаблонов Jinja2.

В этом разделе дается краткое введение в Python API для шаблонов Jinja.

Самый простой способ создать шаблон и отрендерить его - использовать класс jinja2.Template(). Такой способ работы не рекомендуется, если шаблоны загружаются не из строк, а из файловой системы или другого источника данных:

>>> from jinja2 import Template
>>> template = Template('Hello {{ name }}!')
>>> template.render(name='John Doe')
# 'Hello John Doe!'

>>> content = {'a': 5, 'b': 2}
>>> tpl = 'Сумма чисел {{ a }} и {{ b }} равна {{ a + b }}'
>>> Template(tpl).render(content)
# 'Сумма чисел 5 и 2 равна 7'

Пример разбора шаблона с циклом.

>>> import jinja2
# шаблон с циклом
>>> tpl = """{{ title }}
... {{ '-' * title|length }}
... {% for n, user in enumerate(users, 1) %}
... {{ n }}. {{ user.name }} - должность: {{ user.status }}, оклад: ${{ user.salary }}
... {% endfor %}
... """
# собираем данные для шаблона
>>> content = {}
>>> content['title'] = 'Итерация по пользователям'
>>> content['users'] = []
>>> content['users'].append({'name': 'Маша', 'status': 'Менеджер', 'salary': 1500}) 
>>> content['users'].append({'name': 'Света', 'status': 'Дизайнер', 'salary': 1000}) 
>>> content['users'].append({'name': 'Игорь', 'status': 'Программист', 'salary': 2000}) 
# В словаре передаем в шаблон функцию Python
>>> content['enumerate'] = enumerate
# Смотрим, что получилось
>>> print(jinja2.Template(tpl, trim_blocks=True).render(content))
# Итерация по пользователям
# -------------------------
# 1. Маша - должность: Менеджер, оклад: $1500
# 2. Света - должность: Дизайнер, оклад: $1000
# 3. Игорь - должность: Программист, оклад: $2000

Загрузка шаблонов из файловой системы.

Сохраним шаблон из предыдущего примера в директорию ~/temp/main.txt.

{# файл ~/temp/main.txt #}
{{ title }}
{# Добавим условие #}
{% if title %}
{# Если существует переменная `title`, то будем ее подчеркивать #}
{{ '-' * title|length }}
{% endif %}
{# Цикл по пользователям #}
{% for n, user in enumerate(users, 1) %}
{{ n }}. {{ user.name }} - должность: {{ user.status }}, оклад: ${{ user.salary }}
{% endfor %}

Основной код программы, которая работает с сохраненным шаблоном main.txt. Для понимания, что происходит, код снабжен подробными комментариями.

import jinja2
 
# Определяем класс загрузчика шаблонов из файловой системы
# (`temp` - папка где лежит сохраненный шаблон 'main.txt')
loader = jinja2.FileSystemLoader('temp')
# Определяем переменную среду, 
# в которую передаем загрузчик
env = jinja2.Environment(loader=loader, trim_blocks=True)

# данные для шаблона
content = {}
content['title'] = 'Итерация по пользователям'
content['users'] = []
content['users'].append({'name': 'Маша', 'status': 'Менеджер', 'salary': 1500}) 
content['users'].append({'name': 'Света', 'status': 'Дизайнер', 'salary': 1000}) 
content['users'].append({'name': 'Игорь', 'status': 'Программист', 'salary': 2000}) 
# В словаре передаем в шаблон функцию Python
content['enumerate'] = enumerate

# загружаем шаблон 'main.txt'
tpl = env.get_template('main.txt')
# рендерим шаблон в переменную `result`
result = tpl.render(content)
# Сохраним получившийся текст
with open('result.txt', 'w') as fp: 
    fp.write(result)

# Прочитаем записанный файл
with open('result.txt', 'r') as fp: 
    print(fp.read())

# Итерация по пользователям
# -------------------------
# 1. Маша - должность: Менеджер, оклад: $1500
# 2. Света - должность: Дизайнер, оклад: $1000
# 3. Игорь - должность: Программист, оклад: $2000