Шаблоны, часть 2

⏱ 20 мин · 🧩 заданий: 6

Проблема: повторяющийся HTML

У всех страниц сайта есть общие части: <head>, шапка с меню, подвал. Копировать их в каждый шаблон — нарушение DRY. Решение — наследование шаблонов.

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

templates/base.html:

{% load static %}
<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>{% block title %}Мой сайт{% endblock %}</title>
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
  <nav>
    <a href="{% url 'index' %}">Главная</a>
    <a href="{% url 'blog:post_list' %}">Блог</a>
  </nav>

  <main>
    {% block content %}{% endblock %}
  </main>

  <footer>© 2026</footer>
</body>
</html>

{% block имя %} — «дырка», которую дочерние шаблоны могут заполнить. Содержимое внутри блока в базовом шаблоне — значение по умолчанию.

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

blog/templates/blog/post_list.html:

{% extends "base.html" %}

{% block title %}Блог — {{ block.super }}{% endblock %}

{% block content %}
  <h1>Все посты</h1>
  {% for post in posts %}
    <h2><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
  {% endfor %}
{% endblock %}

Правила:

  1. {% extends %} — первый тег в файле.
  2. Всё, что вне блоков, в дочернем шаблоне игнорируется.
  3. {{ block.super }} вставляет содержимое блока из родителя (здесь заголовок будет «Блог — Мой сайт»).
  4. Наследование может быть многоуровневым: base.html → blog/base.html → blog/post_list.html.

Сайт, на котором вы учитесь, устроен так же: все страницы наследуют base.html, где есть шапка с меню и подвал.

include: переиспользуемые фрагменты

Если один и тот же кусок (например, карточка поста) нужен на разных страницах, вынесите его в отдельный файл:

{# blog/_post_card.html #}
<article class="card">
  <h2>{{ post.title }}</h2>
  <p>{{ post.body|truncatewords:30 }}</p>
</article>
{% for post in posts %}
  {% include "blog/_post_card.html" %}
{% endfor %}

{% include "blog/_post_card.html" with post=featured_post only %}

with передаёт переменные, only — запрещает фрагменту видеть остальной контекст. Подчёркивание в имени — просто соглашение: «это фрагмент, а не страница».

Статические файлы

CSS, JavaScript, картинки оформления — статические файлы. Они лежат в папке static/ приложения (или проекта):

blog/static/blog/css/blog.css
static/css/style.css
static/img/logo.png

Настройки:

STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]   # общая папка проекта
STATIC_ROOT = BASE_DIR / "staticfiles"     # куда collectstatic соберёт всё для продакшена

В шаблоне:

{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<img src="{% static 'img/logo.png' %}" alt="Логотип">
<script src="{% static 'js/app.js' %}"></script>

Тег {% static %} строит правильный адрес с учётом STATIC_URL. В режиме разработки (DEBUG = True) runserver раздаёт статику сам, а в продакшене этим займётся NGINX (модуль «Деплой»).

Тег with

Позволяет сохранить результат «дорогого» выражения в короткую переменную:

{% with total=post.comments.count %}
  <p>Комментариев: {{ total }}</p>
{% endwith %}

Контекстные процессоры

Некоторые переменные доступны в любом шаблоне, хотя view их не передавала. Их добавляют контекстные процессоры из настройки TEMPLATES["OPTIONS"]["context_processors"]:

  • request — текущий запрос (request.path, request.GET);
  • user — текущий пользователь (user.is_authenticated, user.username);
  • messages — флеш-сообщения («Пост сохранён»).

Свой процессор — функция, которая принимает request и возвращает словарь:

# blog/context_processors.py
from .models import Category


def categories(request):
    return {"all_categories": Category.objects.all()}

После добавления "blog.context_processors.categories" в настройки переменная all_categories будет доступна везде — удобно для меню.

Итог

  • Базовый шаблон с {% block %}, дочерние — с {% extends %} первой строкой.
  • {% include %} — для повторяющихся фрагментов.
  • Статика подключается через {% load static %} и {% static 'путь' %}.
  • Контекстные процессоры добавляют переменные во все шаблоны.

Практика решено 0 из 6

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Один вариант ответа

Где в дочернем шаблоне должен стоять тег {% extends %}?

Задание 2 Написать код

Напишите дочерний шаблон, который наследует base.html, задаёт блок title с текстом Блог и блок content с заголовком <h1>Все посты</h1>.

Задание 3 Один вариант ответа

Что делает {{ block.super }} внутри блока?

Задание 4 Написать код

Подключите в шаблоне файл стилей css/blog.css из статических файлов. Не забудьте загрузить библиотеку тегов static.

Задание 5 Ввод ответа

Каким тегом вставить в шаблон фрагмент из файла blog/_post_card.html? Напишите тег целиком.

Задание 6 Несколько вариантов

Какие переменные доступны в любом шаблоне благодаря стандартным контекстным процессорам?

Войдите, чтобы отмечать пройденные уроки.