Модуль Jinja2
- это современный и удобный язык шаблонов для Python, созданный по образцу шаблонов Django. Он быстр, т.к. компилируется в код Python, широко используется и безопасен благодаря дополнительной среде выполнения изолированных шаблонов:
Преимущества языка шаблонов Jinja2:
# создаем виртуальное окружение, если нет $ python3 -m venv .venv --prompt VirtualEnv # активируем виртуальное окружение $ source .venv/bin/activate # ставим модуль Jinja2 (VirtualEnv):~$ python -m pip install -U Jinja2
Модуль 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_]*)*
.
В этом разделе дается краткое введение в 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