Когда проект разрастается, каждая новая страница начинает напоминать предыдущую: везде повторяется HTML-разметка, меню, шапка, подвал. Ты копируешь один и тот же код снова и снова, и вроде всё работает… пока не приходится внести изменения.
Допустим, нужно добавить новый пункт меню. Ты вносишь правки в одном шаблоне, потом во втором, третьем, и где-то обязательно забудешь. Результат — хаос.
Чтобы избежать дублирования и облегчить поддержку, в Django есть мощный инструмент — наследование шаблонов.
Допустим, в нашем проекте CinemaHub есть две страницы:
- главная (
index.html); - страница "О сайте" (
about.html).
На обеих страницах одно и то же меню и структура документа.
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<ul>
<li><a href="{% url 'home' %}">Главная</a></li>
{% for m in menu %}
<li><a href="{% url m.url_name %}">{{ m.title }}</a></li>
{% endfor %}
</ul>
<h1>{{ title }}</h1>
<p>Контент страницы...</p>
</body>
</html>Проблема в том, что этот код повторяется в каждом шаблоне. Это нарушает один из главных принципов программирования — DRY (Don't Repeat Yourself).
Чтобы решить проблему, мы создаём один базовый шаблон, от которого будут наследоваться все остальные.
Создай директорию templates в корне проекта и добавь туда файл base.html:
cinemahub/
├── manage.py
├── cinemahub/
│ ├── settings.py
│ ├── urls.py
│ └── ...
└── templates/
└── base.html
<!DOCTYPE html>
<html lang="ru">
<head>
<title>{{ title }}</title>
</head>
<body>
<ul>
<li><a href="{% url 'home' %}">Главная</a></li>
{% for m in menu %}
<li><a href="{% url m.url_name %}">{{ m.title }}</a></li>
{% endfor %}
</ul>
{% block content %}{% endblock %}
</body>
</html>Строка {% block content %}{% endblock %} определяет область, которую дочерние шаблоны смогут заполнять собственным контентом.
Всё остальное — меню, структура HTML — останется общим.
Теперь изменим шаблон index.html, чтобы он наследовал базовую структуру:
{% extends 'base.html' %}
{% block content %}
<h1>{{ title }}</h1>
<ul>
{% for film in films %}
<li>
<h2>{{ film.title }}</h2>
<p>{{ film.description }}</p>
</li>
{% endfor %}
</ul>
{% endblock %}А вот шаблон about.html:
{% extends 'base.html' %}
{% block content %}
<h1>{{ title }}</h1>
<p>Этот сайт создан для любителей кино. Здесь вы найдете подборки фильмов и сериалов со всего мира.</p>
{% endblock %}Теперь оба шаблона используют общую структуру, и если ты захочешь поменять меню или шапку — достаточно отредактировать только один файл base.html.
Чтобы Django понимал, где искать шаблоны (в том числе base.html), убедись, что в settings.py добавлена папка templates:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # 🔹 вот эта строка важна
'APP_DIRS': True,
...
},
]Теперь Django будет искать шаблоны не только внутри приложений, но и в этой общей директории.
# movies/views.py
def about(request):
data = {
"title": "О сайте",
"menu": menu,
"films": data_db,
}
return render(request, "movies/about.html", data)✅ Запусти сервер:
python manage.py runserver
✅ Перейди на главную страницу (/) — должен открыться список фильмов.
✅ Затем перейди на /about/ — структура та же, но контент другой.
Теперь любое изменение в base.html отразится сразу на всех страницах.
Это и есть наследование шаблонов в действии.
Иногда не нужно создавать новый шаблон, достаточно вставить повторяющийся кусок в разные страницы.
Для этого используется тег {% include %}.
Создадим меню как отдельный файл:
movies/templates/movies/includes/nav.html:
<nav>
<a href="{% url 'home' %}">Главная</a> |
<a href="#">Популярное</a> |
<a href="#">Новинки</a> |
<a href="#">Контакты</a>
</nav>Теперь подключим это меню в базовом шаблоне base.html:
<body>
{% include 'movies/includes/nav.html' %}
{% block content %}{% endblock %}
</body>После сохранения и перезагрузки страницы меню появится на всех страницах, где используется base.html.
-
Доступ к переменным: Вставленный шаблон имеет доступ ко всем переменным, которые передаются в контексте.
-
Запрет передачи данных: Если хочешь вставить шаблон без доступа к контексту — добавь
only:{% include 'movies/includes/nav.html' only %} -
Передача отдельных переменных: Можно передавать конкретные значения:
{% include 'movies/includes/nav.html' with section_title='Популярное' %}
- Удали меню из
index.htmlиabout.html, оставив только блокcontent. - Проверь, что меню всё равно отображается (потому что теперь оно в
base.html). - Измени один пункт в
nav.html— например, добавь ссылку "Премьеры". - Обнови страницу — изменение появится во всех шаблонах сразу.
Вот оно — настоящее удобство переиспользования!
- Зачем нужно наследование шаблонов в Django?
- Что делает тег
{% extends %}? - Для чего используется блок
{% block content %}? - Что произойдёт, если удалить
{% endblock %}? - Где нужно указывать путь к базовому шаблону в
settings.py? - Какой тег позволяет вставлять фрагменты кода в шаблон?
- Для чего используется ключевое слово
onlyв теге{% include %}? - Можно ли передавать параметры при подключении шаблона через
include? - Что произойдёт, если изменить код в
base.html? - Почему наследование шаблонов помогает соблюдать принцип DRY?