Глава 22 · Веб-разработка с Python

Jinja: шаблоны HTML с данными

HTML-шаблон с выражениями Jinja и данными из Python — и встроенная защита от случайно выполненной разметки.

Раздел 22.5 уже использовал шаблоны — теперь разберём, как устроен движок Jinja, который Flask использует по умолчанию. Шаблон — обычный HTML-файл, куда вставлены два вида конструкций: {{ выражение }} (вывести значение) и {% команда %} (условие, цикл, наследование).

templates/spisok.html
<ul>
  {% for zadacha in zadachi %}
    <li>{{ zadacha.title }}</li>
  {% endfor %}
</ul>

{% if not zadachi %}
  <p>Задач пока нет.</p>
{% endif %}

Автоэкранирование — Jinja защищает вас по умолчанию

Если значение, которое вставляет {{ }}, содержит HTML-разметку (например, пользователь ввёл в поле <b>), Jinja по умолчанию экранирует специальные символы — превращает < в &lt; и так далее. Браузер покажет это как обычный текст, а не выполнит как разметку. Это называют автоэкранированием (autoescaping), и оно включено для HTML-шаблонов Flask по умолчанию.

|safe отключает именно эту защиту
У Jinja есть фильтр |safe, который отключает автоэкранирование для конкретного значения — Jinja вставит его как есть, включая любую разметку. Это уместно для текста, который вы полностью контролируете сами (например, HTML, зашитый в код приложения), но не для данных, которые ввёл пользователь: к чему это приводит на практике, показывает раздел 22.32. Если сомневаетесь — не добавляйте |safe.

Наследование шаблонов — общий каркас страницы

Чтобы не повторять <head>, навигацию и подключение CSS в каждом шаблоне, заводят базовый шаблон с именованными блоками, которые заполняют дочерние шаблоны:

templates/base.html
<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>{% block title %}Список задач{% endblock %}</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
  {% block content %}{% endblock %}
</body>
</html>
templates/index.html
{% extends "base.html" %}

{% block content %}
  <h1>Мой список задач</h1>
  ...
{% endblock %}

{% extends "base.html" %} говорит: «возьми базовый шаблон и подставь моё содержимое в отмеченные блоки». Итоговый проект главы (раздел 22.35) использует именно эту структуру — base.html и несколько дочерних шаблонов.

Практика: шаблоны и автоэкранирование
Модуль flask не установлен в браузерном окружении Pyodide — выполните локально в VS Code, PyCharm или Jupyter
Практика выполняется локально
Открыть практику →