Наследование шаблонов в Django: пошаговая инструкция
За полчаса вы соберёте базовый шаблон с блоками, унаследуете от него три страницы и перестанете копировать шапку и подвал по всему проекту.

Если в вашем Django-проекте шапка сайта, меню и подвал скопированы в каждый HTML-файл, любое изменение в меню превращается в правку пяти файлов. Наследование шаблонов решает это за один раз: вы описываете общий каркас в базовом файле, а конкретные страницы переопределяют только то, что у них своё. К концу инструкции у вас будет один base.html и три страницы, которые от него наследуются. Времени — около 30 минут. Всё написано для Django 5.x, но синтаксис тегов extends и block не менялся с ранних версий 1.x, так что подойдёт и для 4.x.
Что нужно до начала
Перед первым шагом убедитесь, что у вас есть:
- установленный Python 3.10+ и Django 5.x (проверьте командой
python -m django --version); - созданный проект и хотя бы одно приложение (
python manage.py startapp pages); - приложение добавлено в
INSTALLED_APPSвsettings.py; - настроенная папка для шаблонов — об этом первый шаг.
Если проекта ещё нет, создайте его командой django-admin startproject mysite и внутри — приложение. Дальше все пути привязаны к структуре, где settings.py лежит в mysite/mysite/.
Куда Django ищет шаблоны
Есть два подхода к расположению шаблонов, и от выбора зависит первый шаг.
- Внутри приложения:
pages/templates/pages/. Django находит их автоматически, если в настройках включёнAPP_DIRS. - Общая папка проекта:
templates/в корне. Удобнее для базовых шаблонов, которые делят несколько приложений. Нужно явно указать путь в настройках.
Базовый шаблон логично держать общим, поэтому используем второй вариант.
Шаг 1. Настроить папку шаблонов
Создайте папку templates в корне проекта — рядом с manage.py. Откройте settings.py и найдите список TEMPLATES. В нём есть ключ DIRS — добавьте туда путь:
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
# общая папка templates в корне проекта
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
Проверка: путь BASE_DIR / "templates" ведёт в только что созданную папку. Если BASE_DIR в вашем settings.py объявлен иначе, ориентируйтесь на то, что DIRS должен указывать на папку рядом с manage.py.
Шаг 2. Написать базовый шаблон
Создайте файл templates/base.html. В нём — общий каркас: <head>, шапка, подвал. Места, которые страницы будут переопределять, отмечаются тегом {% block %}.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>{% block title %}Мой сайт{% endblock %}</title>
</head>
<body>
<header>
<a href="/">Главная</a> |
<a href="/about/">О нас</a>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2024 Мой сайт</p>
</footer>
</body>
</html>
Здесь два блока. title с текстом по умолчанию «Мой сайт» — если страница его не переопределит, останется это значение. content пустой — его заполнит каждая страница своим.
Проверка: файл лежит по пути templates/base.html, теги {% block %} закрыты парным {% endblock %}. Незакрытый блок — самая частая причина ошибки шаблона.
Базовый шаблон — это форма с прорезями. Блоки — прорези. Дочерний шаблон не переписывает форму, он вставляет своё содержимое в прорези.
Шаг 3. Унаследовать первую страницу
Создайте templates/home.html. Первой строкой обязательно идёт {% extends %} — до неё в файле не должно быть ничего, даже пробельной строки с текстом.
{% extends "base.html" %}
{% block title %}Главная — Мой сайт{% endblock %}
{% block content %}
<h1>Добро пожаловать</h1>
<p>Это главная страница.</p>
{% endblock %}
Django возьмёт каркас из base.html, подставит в блок title новый текст, а в content — заголовок и абзац. Шапка и подвал придут из базового файла автоматически.
Шаг 4. Подключить шаблон к представлению
Чтобы страница открылась в браузере, нужны представление и маршрут. В pages/views.py:
from django.shortcuts import render
def home(request):
return render(request, "home.html")
В mysite/urls.py (тот, что рядом с settings.py):
from django.contrib import admin
from django.urls import path
from pages import views
urlpatterns = [
path("admin/", admin.site.urls),
path("", views.home, name="home"),
]
Проверка: запустите python manage.py runserver и откройте http://127.0.0.1:8000/. В браузере должна появиться шапка со ссылками, заголовок «Добро пожаловать» и подвал с копирайтом. Во вкладке браузера — «Главная — Мой сайт».
Шаг 5. Добавить ещё две страницы
Теперь видно, как быстро добавлять новое. Создайте templates/about.html и templates/contact.html по тому же образцу — меняется только содержимое блоков:
{% extends "base.html" %}
{% block title %}О нас — Мой сайт{% endblock %}
{% block content %}
<h1>О компании</h1%>
<p>Здесь текст о нас.</p>
{% endblock %}
Добавьте представления и маршруты path("about/", views.about, name="about") и path("contact/", ...) по аналогии с шагом 4. Никакой шапки и подвала в этих файлах нет — и это главное: они описаны один раз в base.html.
Проверка: все три страницы открываются, шапка и подвал одинаковые. Измените ссылку в шапке в base.html — изменение появится сразу на всех трёх страницах.
Один приём, который экономит время: block.super
Иногда нужно не заменить содержимое блока целиком, а добавить к нему своё. Тег {{ block.super }} вставляет содержимое родительского блока внутрь дочернего. Полезно для заголовков вкладок:
{% block title %}Контакты — {{ block.super }}{% endblock %}
Если в базовом блоке title было «Мой сайт», результат — «Контакты — Мой сайт». Так вы не дублируете название сайта на каждой странице.
Если не получилось
Четыре ошибки, на которые уходит больше всего времени у новичков.
TemplateDoesNotExist at /— Django не нашёл файл. Проверьте путь вDIRSи точное имя файла. Django чувствителен к регистру:Base.htmlиbase.html— разные файлы.Invalid block tag on line 1: 'extends'— обычно опечатка в теге или лишний символ перед{% extends %}. Строка сextendsдолжна быть самой первой в файле.- Страница открывается, но пустая, без шапки — скорее всего забыли
{% extends "base.html" %}или неверно указали имя базового файла в кавычках. Unclosed tag on line N. Looking for one of: endblock— где-то не закрыт{% block %}. Каждомуblockнужен свойendblock.
Ещё одна тонкость: содержимое, написанное в дочернем шаблоне вне любого блока, Django просто игнорирует. Если ваш HTML не появляется на странице — проверьте, что он внутри {% block content %}...{% endblock %}.
Что делать дальше
Когда каркас работает, следующие шаги такие:
- вынесите повторяющиеся куски (карточка товара, форма) в отдельные файлы и подключайте тегом
{% include "partial.html" %}— это дополнение к наследованию, а не замена; - для статики (CSS, JS) подключите приложение
django.contrib.staticfilesи используйте тег{% load static %}в базовом шаблоне; - если базовый шаблон разрастается, выделите промежуточный слой:
base.html→base_dashboard.html→ конкретные страницы. Django поддерживает цепочку наследования любой глубины.
Многоуровневое наследование и передача данных в шаблон через контекст представления — отдельные темы, здесь мы разобрали только базовый механизм extends и block. Точное поведение тегов сверяйте с документацией Django вашей версии.
Антиблок-аналитик 115-ФЗ: Анализ выписок, поиск рисков блокировки счёта, инструкции по безопасным транзакциям.
Спросить за 41 ₽Источники: Django Templates — официальная документация, Template inheritance — Django docs
Частые вопросы
У меня Django 4.2, а не 5.x — инструкция подойдёт?
Что делать, если появилась ошибка TemplateDoesNotExist?
Можно ли наследоваться от шаблона, который сам от кого-то наследуется?
Чем отличается extends от include?
Почему мой HTML в дочернем шаблоне не отображается?
Обязательно ли держать base.html в общей папке, а не внутри приложения?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.