Наследование шаблонов: base, block, extends
Наследование шаблонов — это базовый «скелет» сайта (шапка, меню, подвал) с дырками-блоками, которые каждая страница заполняет по-своему. Один каркас — десятки страниц.
Без наследования шапку и подвал пришлось бы копировать в каждый шаблон. Базовый шаблон описывает общую структуру и оставляет блоки; дочерние шаблоны наследуют его через extends и переопределяют нужные блоки. Это самая мощная часть Jinja.
Любой сайт имеет общие части: меню, футер, подключение CSS. Дублировать их в каждом файле — кошмар поддержки (поменял меню — правь в двадцати местах). Наследование решает это: общее живёт в base.html, страницы лишь подставляют своё содержимое.
Базовый шаблон templates/base.html:
<!DOCTYPE html>
<html>
<head><title>{% block title %}Сайт{% endblock %}</title></head>
<body>
<nav>Меню</nav>
{% block content %}{% endblock %}
<footer>Подвал</footer>
</body>
</html>
Дочерний шаблон templates/page.html:
{% extends "base.html" %}
{% block title %}Главная{% endblock %}
{% block content %}
<h1>Добро пожаловать</h1>
{% endblock %}
Директива {% extends %} говорит «возьми каркас base.html», а блоки переопределяют дырки. Внутри блока можно вызвать {{ super() }} — он вставит содержимое родительского блока, чтобы дополнить, а не заменить его.
Наследование шаблонов — это применение принципа DRY (не повторяйся) к вёрстке. Один base.html описывает общий каркас, и любая правка шапки, меню или подключения стилей делается в одном файле, мгновенно отражаясь на всех страницах. На больших проектах строят иерархию в несколько уровней: глобальный base.html, под ним layout раздела (свой сайдбар у админки, свой — у блога), под ним конкретные страницы. К наследованию примыкают два соседних инструмента: {% include %} вставляет переиспользуемый фрагмент (карточка товара, форма поиска), а макросы — это «функции для разметки», принимающие параметры. Вместе они полностью устраняют копипасту HTML.
Как работает под капотом
При extends Jinja берёт структуру родителя как основу, а из дочернего шаблона использует только содержимое блоков с совпадающими именами. Дочерний шаблон не «дописывается снизу» — он встраивается в дырки родителя.
base.html page.html (extends base)
┌───────────────┐ переопределяет:
│ title: [блок] │◀──────── title = "Главная"
│ nav │ content= "<h1>..."
│ content:[блок]│◀────────┘
│ footer │
└───────────────┘
│ слияние
▼
итог: nav+footer из base, title+content из page
Смоделируем слияние «скелет + блоки» обычным Python.
base_blocks = {"title": "Сайт", "content": "(пусто)"}
base_skeleton = "[head:{title}] [nav] [{content}] [footer]"
def render_child(child_blocks):
blocks = dict(base_blocks) # берём дефолты родителя
blocks.update(child_blocks) # переопределяем своими
return base_skeleton.format(**blocks)
print(render_child({"title": "Главная", "content": "Привет"}))
print(render_child({"title": "О нас"})) # content остался дефолтным
Запусти: дочерние блоки переопределяют дырки родителя, а нетронутые блоки берут значение по умолчанию. nav и footer всегда из base — их не копируем. Так наследование убивает дублирование.
Частые ошибки
- Контент вне блоков в дочернем шаблоне. Всё, что не в {% block %}, при extends игнорируется.
- extends не первой строкой. Директива extends должна идти в начале файла.
- Забыть super() и затереть родительский блок. Если хочешь дополнить, а не заменить — вызови {{ super() }}.
Best practices
- Один base.html на проект (или несколько уровней: base → layout раздела → страница).
- Выноси повторяющиеся куски в {% include %} (карточка, меню) и макросы.
- Имена блоков осмысленные: content, title, sidebar, scripts.
Что запомнить
- base.html задаёт общий каркас сайта с блоками-дырками.
- Дочерний шаблон через extends переопределяет нужные блоки.
- {{ super() }} вставляет содержимое родительского блока для дополнения.
- include и макросы дополняют наследование для переиспользования фрагментов.
Итог: наследование задаёт общий каркас в base.html с блоками, а страницы через extends заполняют только свои части. super() позволяет дополнять родителя. Это устраняет дублирование разметки. Дальше — безопасность шаблонов и автоэкранирование.