Skip to content

Latest commit

 

History

History
255 lines (187 loc) · 9.02 KB

File metadata and controls

255 lines (187 loc) · 9.02 KB

Модуль 2. Урок 11. Наследование шаблонов (extends) и тег include

Когда проект разрастается, каждая новая страница начинает напоминать предыдущую: везде повторяется HTML-разметка, меню, шапка, подвал. Ты копируешь один и тот же код снова и снова, и вроде всё работает… пока не приходится внести изменения.

Допустим, нужно добавить новый пункт меню. Ты вносишь правки в одном шаблоне, потом во втором, третьем, и где-то обязательно забудешь. Результат — хаос.

Чтобы избежать дублирования и облегчить поддержку, в Django есть мощный инструмент — наследование шаблонов.


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

Допустим, в нашем проекте 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).


2. Создаём базовый шаблон base.html

Чтобы решить проблему, мы создаём один базовый шаблон, от которого будут наследоваться все остальные.

Создай директорию templates в корне проекта и добавь туда файл base.html:

cinemahub/
├── manage.py
├── cinemahub/
│   ├── settings.py
│   ├── urls.py
│   └── ...
└── templates/
    └── base.html

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 — останется общим.


3. Подключаем базовый шаблон через {% extends %}

Теперь изменим шаблон 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.


4. Добавляем шаблонный путь в settings.py

Чтобы Django понимал, где искать шаблоны (в том числе base.html), убедись, что в settings.py добавлена папка templates:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],  # 🔹 вот эта строка важна
        'APP_DIRS': True,
        ...
    },
]

Теперь Django будет искать шаблоны не только внутри приложений, но и в этой общей директории.

5. Изменяем представление about во views.py

# movies/views.py
def about(request):
    data = {
        "title": "О сайте",
        "menu": menu,
        "films": data_db,
    }
    return render(request, "movies/about.html", data)

6. Проверка в браузере

✅ Запусти сервер:

python manage.py runserver

✅ Перейди на главную страницу (/) — должен открыться список фильмов. ✅ Затем перейди на /about/ — структура та же, но контент другой.

Теперь любое изменение в base.html отразится сразу на всех страницах. Это и есть наследование шаблонов в действии.


6. Подключение фрагментов: тег {% include %}

Иногда не нужно создавать новый шаблон, достаточно вставить повторяющийся кусок в разные страницы. Для этого используется тег {% 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.


Особенности include

  1. Доступ к переменным: Вставленный шаблон имеет доступ ко всем переменным, которые передаются в контексте.

  2. Запрет передачи данных: Если хочешь вставить шаблон без доступа к контексту — добавь only:

    {% include 'movies/includes/nav.html' only %}
  3. Передача отдельных переменных: Можно передавать конкретные значения:

    {% include 'movies/includes/nav.html' with section_title='Популярное' %}

Проверка результата

  1. Удали меню из index.html и about.html, оставив только блок content.
  2. Проверь, что меню всё равно отображается (потому что теперь оно в base.html).
  3. Измени один пункт в nav.html — например, добавь ссылку "Премьеры".
  4. Обнови страницу — изменение появится во всех шаблонах сразу.

Вот оно — настоящее удобство переиспользования!


Вопросы

  1. Зачем нужно наследование шаблонов в Django?
  2. Что делает тег {% extends %}?
  3. Для чего используется блок {% block content %}?
  4. Что произойдёт, если удалить {% endblock %}?
  5. Где нужно указывать путь к базовому шаблону в settings.py?
  6. Какой тег позволяет вставлять фрагменты кода в шаблон?
  7. Для чего используется ключевое слово only в теге {% include %}?
  8. Можно ли передавать параметры при подключении шаблона через include?
  9. Что произойдёт, если изменить код в base.html?
  10. Почему наследование шаблонов помогает соблюдать принцип DRY?

Предыдущий урок | Следующий урок