Наследование шаблонов: extends и блоки

Без наследования шаблонов вы будете копировать шапку, меню и подвал в каждый файл. Django решает это блоками: один базовый каркас, много страниц-наследников.
Суть: базовый шаблон задаёт каркас с именованными блоками, дочерние шаблоны его расширяют через extends и переопределяют только нужные блоки. include вставляет переиспользуемые фрагменты.

Проблема дублирования

Каждая страница сайта имеет общую обвязку: <head> с метатегами, шапку с меню, подвал, подключение стилей. Копировать всё это в десятки шаблонов — путь к аду сопровождения: поменяли меню — правьте в сорока местах. Наследование шаблонов решает проблему радикально.

Базовый шаблон

Создаём base.html — каркас с «дырками», помеченными тегом {% block %}:

<!DOCTYPE html>
<html lang="ru">
<head>
  <title>{% block title %}Мой сайт{% endblock %}</title>
</head>
<body>
  <header>Шапка и меню</header>
  <main>
    {% block content %}{% endblock %}
  </main>
  <footer>Подвал</footer>
</body>
</html>

Дочерний шаблон

Конкретная страница расширяет базовый через {% extends %} (это должна быть первая строка) и переопределяет только нужные блоки:

{% extends "base.html" %}

{% block title %}Список постов{% endblock %}

{% block content %}
  <h1>Посты</h1>
  {% for post in posts %}
    <article>{{ post.title }}</article>
  {% endfor %}
{% endblock %}

Шапка, подвал и весь каркас наследуются автоматически. Вы пишете только содержимое страницы.

base.html  (каркас + блоки)
   ▲  extends
   │
post_list.html ── переопределяет block title и block content
   │
post_detail.html ── переопределяет те же блоки по-своему

include для фрагментов

Если нужно вставить переиспользуемый кусок (карточку поста, виджет), используют {% include %}: {% include "blog/_card.html" with post=post %}. Так одна карточка применяется и в списке, и на главной.

Как это работает под капотом

Движок собирает финальную страницу так: берёт каркас базового шаблона и подставляет в его блоки содержимое из дочернего, а где дочерний блок не задан — оставляет содержимое из базового. Это языко-независимая логика «слияния словарей блоков». Вот её модель:

# Попробуй сам ▶ — слияние блоков base + child
base_blocks = {
    "title":   "Мой сайт",
    "content": "(пусто)",
    "footer":  "© 2026",
}

child_blocks = {                      # дочерний переопределяет часть
    "title":   "Список постов",
    "content": "Здесь список из 10 постов",
}

# extends: дочерние блоки перекрывают базовые, остальное наследуется
final = {**base_blocks, **child_blocks}

print("Итоговая страница:")
for name, value in final.items():
    source = "child" if name in child_blocks else "base"
    print(f"  [{name:8}] = {value!r:35} ({source})")

Django делает ровно это: блоки дочернего шаблона перекрывают одноимённые блоки базового, ненайденные наследуются. Можно даже дополнить родительский блок через {{ block.super }}.

Где лежат шаблоны

Django ищет шаблоны в папках templates/ внутри приложений (если включён APP_DIRS) и в путях из DIRS. Чтобы избежать конфликтов имён между приложениями, шаблоны кладут в подпапку с именем приложения: blog/templates/blog/post_list.html.

Три уровня шаблонов: приём для крупных проектов

На больших сайтах одного base.html мало: разделы (блог, магазин, личный кабинет) имеют общую обвязку сайта, но свою внутреннюю структуру. Решение — трёхуровневая иерархия. Самый верхний base.html задаёт скелет всего сайта: шапку, подвал, подключение стилей и крупные блоки. Промежуточные шаблоны вроде blog/base.html расширяют его и добавляют боковую панель раздела, оставляя блок content открытым. А конкретные страницы наследуют уже от промежуточного. Так каждый уровень отвечает за свой слой разметки, и изменение в одном месте аккуратно распространяется вниз по всей цепочке. Этот приём — прямое следствие того, что extends можно выстраивать в цепочку любой глубины: дочерний шаблон сам может быть базовым для следующего.

Частые ошибки

  • Ставить {% extends %} не первой строкой. Он обязан быть в самом начале файла.
  • Не класть шаблоны в подпапку приложения. Будут конфликты имён между приложениями.
  • Дублировать каркас вместо наследования. Это сводит на нет всю идею.
  • Забыть {% endblock %}. Блоки парные.

Best practices

  • Держите один base.html на проект; для разделов — промежуточные базовые шаблоны.
  • Выносите повторяющиеся фрагменты в частичные шаблоны и подключайте через include.
  • Именуйте частичные шаблоны с подчёркиванием: _card.html.
  • Используйте {{ block.super }}, чтобы дополнять, а не затирать базовый блок.

Итоги

Наследование шаблонов убивает дублирование: базовый каркас с блоками плюс дочерние страницы, переопределяющие нужное. extends, block, include — три кита переиспользования разметки. Дальше подключим к страницам стили, скрипты и картинки — статические файлы.

Проверьте себя
1. Каким должен быть тег {% extends %} в дочернем шаблоне?
AПоследним
BПервой строкой файла
CВнутри блока content
DГде угодно
2. Что произойдёт с блоком базового шаблона, если дочерний его не переопределил?
AБлок исчезнет
BОстанется содержимое из базового шаблона
CБудет ошибка
DБлок станет пустым