# Использование Jinja шаблонов ## Введение * **Проблема:** Жестко закодированный HTML или другие текстовые форматы в приложениях затрудняют динамическое формирование контента и разделение логики представления от бизнес-логики. * **Решение:** Использование шаблонизаторов, таких как Jinja, для создания динамических текстовых документов (например, HTML, XML, CSV, конфигурационные файлы). * **Jinja:** Гибкий и мощный шаблонизатор для Python. ## Что такое Jinja? * **Определение:** Шаблонизатор, позволяющий внедрять динамический контент в статические шаблоны. * **Основные принципы:** * **Разделение ответственности:** Отделение логики представления (шаблонов) от бизнес-логики (Python-код). * **Читаемость:** Синтаксис, разработанный для легкости чтения и понимания. * **Мощность:** Поддержка переменных, циклов, условных операторов, фильтров, тестов и макросов. * **Безопасность:** Встроенные механизмы для предотвращения XSS-атак. ## Основные компоненты Jinja шаблонов 1. **Переменные (`{{ ... }}`):** * Используются для отображения данных, переданных из Python-кода в шаблон. * Доступ к атрибутам объекта осуществляется через точку (`.`) или квадратные скобки (`[]`). * **Пример:** ```html+jinja

Привет, {{ user.name }}!

Ваш email: {{ user['email'] }}

``` 2. **Операторы (`{% ... %}`):** * Используются для выполнения логических операций, таких как циклы и условные операторы. * **Условные операторы (`if`, `elif`, `else`):** ```html+jinja {% if user.is_logged_in %}

Добро пожаловать!

{% elif user.has_pending_notifications %}

У вас есть непрочитанные уведомления.

{% else %}

Пожалуйста, войдите.

{% endif %} ``` * **Циклы (`for`):** ```html+jinja ``` * `loop` контекстная переменная внутри цикла: * `loop.index`: Текущий индекс (начиная с 1). * `loop.index0`: Текущий индекс (начиная с 0). * `loop.first`: True, если это первая итерация. * `loop.last`: True, если это последняя итерация. * `loop.length`: Общее количество элементов. * `loop.revindex`: Количество оставшихся элементов (начиная с 1). * `loop.revindex0`: Количество оставшихся элементов (начиная с 0). * **Наследование шаблонов (`extends`, `block`):** * **`extends`:** Указывает на родительский шаблон, который будет расширен. * **`block`:** Определяет области в родительском шаблоне, которые могут быть переопределены в дочерних шаблонах. * **Родительский шаблон (`base.html`):** ```html+jinja {% block title %}Мой сайт{% endblock %}
{% block content %}{% endblock %}
``` * **Дочерний шаблон (`index.html`):** ```html+jinja {% extends 'base.html' %} {% block title %}Главная страница{% endblock %} {% block content %}

Добро пожаловать на главную страницу!

Это содержимое главной страницы.

{% endblock %} ``` * **Включения (`include`):** * Вставляет содержимое другого шаблона в текущий шаблон. * Полезно для повторного использования фрагментов HTML. * **Пример:** ```html+jinja
{% include 'navigation.html' %}
``` 3. **Фильтры (`{{ variable | filter }}`):** * Модифицируют значения переменных перед их отображением. * Применяются с помощью символа `|`. * Можно применять несколько фильтров последовательно (`{{ variable | filter1 | filter2 }}`). * **Примеры встроенных фильтров:** * `capitalize`: Преобразует первую букву в заглавную, остальные в строчные. * `lower`: Преобразует строку в нижний регистр. * `upper`: Преобразует строку в верхний регистр. * `title`: Преобразует первую букву каждого слова в заглавную. * `trim`: Удаляет пробелы с начала и конца строки. * `striptags`: Удаляет HTML/XML теги. * `length`: Возвращает длину последовательности или строки. * `default(value)`: Возвращает указанное значение, если переменная неопределена. * `join(separator)`: Объединяет элементы последовательности в строку с указанным разделителем. * `sort`: Сортирует последовательность. * `format(value, ...)`: Форматирует строку с использованием оператора `%`. * `replace(old, new)`: Заменяет все вхождения подстроки `old` на `new`. * **Пример использования фильтров:** ```html+jinja

{{ message | capitalize }}

Количество элементов: {{ items | length }}

Цена: {{ price | default('Бесплатно') }}

Имена: {{ names | join(', ') }}

``` 4. **Тесты (`{% if variable is test %}`):** * Используются для проверки типа или состояния переменной. * Применяются с помощью ключевого слова `is`. * **Примеры встроенных тестов:** * `defined`: Проверяет, определена ли переменная. * `undefined`: Проверяет, не определена ли переменная. * `none`: Проверяет, является ли переменная `None`. * `number`: Проверяет, является ли переменная числом. * `string`: Проверяет, является ли переменная строкой. * `boolean`: Проверяет, является ли переменная булевым значением. * `iterable`: Проверяет, является ли переменная итерируемым объектом. * `lower`: Проверяет, является ли строка в нижнем регистре. * `upper`: Проверяет, является ли строка в верхнем регистре. * **Пример использования тестов:** ```html+jinja {% if user.age is number and user.age >= 18 %}

Совершеннолетний

{% else %}

Несовершеннолетний

{% endif %} {% if items is iterable and items | length > 0 %} {% else %}

Нет элементов.

{% endif %} ``` 5. **Комментарии (`{# ... #}`):** * Используются для добавления комментариев в шаблон, которые не отображаются в выходном документе. * **Пример:** ```html+jinja {# Это комментарий, который не будет виден в HTML #}

Отображаемый текст.

``` 6. **Макросы (`{% macro name(param1, param2='default') %}`):** * Позволяют определять многократно используемые фрагменты шаблонов (похожи на функции). * Могут принимать аргументы. * Импортируются с помощью `import` или `from ... import ...`. * **Определение макроса:** ```html+jinja {% macro render_user(user) %}

{{ user.name }}

Email: {{ user.email }}

{% endmacro %} ``` * **Использование макроса:** ```html+jinja {% from 'macros.html' import render_user %} {{ render_user(current_user) }} ``` ## Использование Jinja в Python 1. **Установка:** ```bash pip install Jinja2 ``` 2. **Импорт:** ```python from jinja2 import Environment, FileSystemLoader ``` 3. **Создание окружения (`Environment`):** * Загрузчик (`FileSystemLoader`) указывает, где искать файлы шаблонов. ```python env = Environment(loader=FileSystemLoader('.')) # Искать шаблоны в текущей директории # Или указать конкретную папку: env = Environment(loader=FileSystemLoader('templates')) ``` 4. **Загрузка шаблона (`get_template()`):** ```python template = env.get_template('index.html') ``` 5. **Рендеринг шаблона (`render()`):** * Передача данных в шаблон в виде словаря. ```python context = { 'user': {'name': 'Иван', 'email': 'ivan@example.com', 'is_logged_in': True}, 'items': [{'name': 'Яблоко', 'price': 1.0}, {'name': 'Банан', 'price': 0.5}] } rendered_html = template.render(context) print(rendered_html) ``` ## Безопасность Jinja * **Автоматическое экранирование:** Jinja автоматически экранирует HTML-специальные символы (`<`, `>`, `&`, `'`, `"`) для предотвращения XSS-атак. * **Отключение экранирования (`| safe` фильтр):** Используйте с осторожностью для переменных, которые вы абсолютно уверены, что содержат безопасный HTML. ```html+jinja
{{ user.formatted_description | safe }}
``` ## Лучшие практики * **Разделение логики:** Передавайте в шаблоны только необходимые данные для отображения. Вся основная бизнес-логика должна оставаться в Python-коде. * **Использование наследования шаблонов:** Для создания структуры сайта и повторного использования общих элементов. * **Создание макросов для повторно используемых фрагментов:** Упрощает поддержку и улучшает читаемость шаблонов. * **Применение фильтров для форматирования данных:** Делайте это непосредственно в шаблонах для логики представления. * **Осторожное использование `| safe`:** Только когда это действительно необходимо и вы уверены в безопасности HTML-содержимого. * **Организация файлов шаблонов:** Создавайте логическую структуру директорий для удобства поддержки. ## Заключение Jinja является мощным инструментом для динамического формирования текстового контента в Python-приложениях. Понимание его синтаксиса и основных возможностей позволяет создавать гибкие, читаемые и безопасные шаблоны, эффективно разделяя логику представления от бизнес-логики.