Django: шаблон и контекст списка заметок
Оглавление курса · Скачать все состояния проекта.
Учебная задача: Передать список заметок в шаблон и отделить данные от HTML.
Входное состояние: Снимок lesson-02: приложение notes возвращает текст. Выходное состояние: HTML списка из двух словарей, цикл шаблона и пустое состояние. Эта глава продолжает «Редакционный стол» — небольшой сайт заметок. Нужны основы Python, HTML и устройство HTTP-запроса. Используем Python 3.12 и Django 5.2.18 LTS; номер ветки выбран для этой серии. Полный каталог lesson-03 в архиве содержит собственные настройки, шаблоны и историю миграций. При самостоятельном прохождении выберите один снимок и отдельную локальную базу; смешивание файлов разных глав меняет договор примера.
Исходники подготовлены редакционным чтением. Зависимости, миграции, сервер и команды работы с данными здесь не выполнялись. Все описанные ответы и изменения являются ожидаемыми, example_execution: not_run.
До этого ответ страницы был одной строкой в функции Python. Для списка редакционных заметок такая форма неудобна: содержимое данных смешивается с HTML, а добавление второго элемента требует ручной сборки строки. Шаблон позволяет описать структуру документа отдельно, оставив представлению выбор данных. Сейчас используем два обычных словаря. База появится позднее, поэтому на этом шаге легко увидеть, какую работу выполняет именно шаблонизатор.
Контекст — это набор именованных значений, доступных во время формирования страницы. Представление передаёт в render словарь с ключом notes; шаблон обращается к этому имени. Контекст не является глобальным хранилищем и не живёт между запросами автоматически. На следующем запросе функция снова создаст данные и передаст их шаблону. Если в другом представлении имя не передано, нельзя ожидать, что оно сохранилось после посещения списка.
Выбор данных в представлении
В note_list каждый словарь содержит title и body. Имена выражают смысл: заголовок и основной текст заметки. Мы сохраняем их на протяжении курса; после перехода к модели шаблон по-прежнему получит объекты с такими атрибутами. Это облегчает замену источника данных. Замена Python-списка на QuerySet не обязана означать переписывание каждого HTML-тега, если интерфейс данных остаётся согласованным.
Функция render получает запрос, путь шаблона и контекст. Она возвращает HTTP-ответ после обработки шаблона. Путь notes/list.html относится к системе поиска шаблонов, а не к публичному URL. Посетитель не запрашивает файл notes/templates/notes/list.html напрямую. Именно представление решает, какой шаблон использовать. Так один шаблон может обслуживать разные адреса, а один адрес может выбирать разные шаблоны в зависимости от результата обработки.
Вложенный каталог notes внутри templates нужен для различения ресурсов разных приложений. Если два приложения назовут шаблон просто list.html, поиск может найти нежелательный файл. Префикс в пути делает намерение явным: используем список приложения заметок. Настройка APP_DIRS позволяет искать шаблоны внутри зарегистрированных приложений. Поэтому ошибка «шаблон не найден» требует проверки и пути файла, и регистрации приложения, и настройки поиска.
Цикл и подстановка значений
Запись {{ note.title }} подставляет значение в документ. Точки в языке шаблонов умеют обращаться к данным словаря и атрибутам объекта; это не полное выполнение произвольного выражения Python. Теги {% for %} и {% endfor %} задают повторение HTML для каждого элемента. Внутри цикла note означает текущий элемент, а не весь список. После окончания цикла не стройте логику страницы на предположении, что последняя заметка стала отдельной глобальной переменной.
Структура повторяемой части сохраняет семантику: каждая заметка находится в article, её название — в h2, текст — в абзаце. На всей странице есть один главный h1. Это позволяет воспринимать список как документ с понятными уровнями заголовков. Изменение оформления не должно заставлять заменять заголовки произвольными div. Позднее ссылка карточки окажется внутри h2, но роль заголовка элемента останется прежней.
Подстановка по умолчанию экранирует HTML-символы. Если в заголовке окажется <script>, он должен отображаться как текст, а не выполняться. Не добавляйте фильтр safe ради удобства вывода произвольного содержимого. Он меняет доверие к данным и требует отдельного обоснования. В нашей редакционной системе основной текст остаётся обычным текстом; переносы позже оформим подходящим фильтром, сохраняя экранирование опасных символов.
Пустой список и наблюдение результата
Ветка {% empty %} относится к циклу. Она показывается, когда коллекция не содержит элементов. Это отличается от ошибки чтения данных: пустой корректный список сообщает «Заметок пока нет», а неисправное подключение к базе позднее должно обрабатываться как сбой. На этапе обычного Python-списка можете проверить модель поведения мысленно, заменив значение на []. Ожидается один абзац пустого состояния и ни одного пустого блока article.
Для двух исходных заметок ожидаются два раздела в том же порядке, что и словари. Заголовок «Расписание интервью» должен соседствовать с собственным текстом, а не с текстом фотографии. Если вы случайно вынесете note.body за цикл, связь будет нарушена. При редакционном чтении полезно проследить один объект от создания словаря до готовых тегов. Это объясняет результат лучше, чем простое сравнение общего числа элементов.
Измените заголовок второй заметки на строку с амперсандом и угловыми скобками. Смысл упражнения — понять разницу между исходным значением и HTML-представлением, а не получить особый визуальный эффект. Затем уберите все элементы и рассмотрите пустую ветку. В следующей главе общий документ будет вынесен в базовый шаблон: список сохранит только свою предметную часть, а шапка, стили и метаданные станут общими.
Разбор связи файлов
Если в контексте не окажется ключа, который ожидает шаблон, выражение обычно не станет осмысленным сообщением редакции само по себе. Поэтому название ключа notes — часть договора между представлением и страницей. При переименовании изменяются оба участника. Типичная ошибка здесь выглядит как пустое место, хотя данные существуют в Python под другим именем. Проверять нужно передачу контекста, а не немедленно добавлять новую запись.
Цикл работает с последовательностью объектов; сейчас это словари, позже ими станут экземпляры модели. Шаблон читает нужные поля, не зная способа получения всей последовательности. Такая замена возможна, пока сохраняются ожидаемые имена. Именно поэтому не помещаем в шаблон создание словарей или выполнение запросов: он должен объяснять структуру документа, а представление отвечает за подготовку данных.
Обратите внимание на ветку empty. Она относится к отсутствию элементов, а не к ошибке сервера. Пустая редакция после первого развёртывания может быть нормальным состоянием. Сообщение «Заметок пока нет» даёт человеку понятный следующий шаг, тогда как техническое исключение означает иной сбой. Для самостоятельного разбора сравните пустой список с отсутствующим ключом контекста и с неверным именем файла шаблона: внешне проблемы могут выглядеть похоже, но исправляются в разных местах.
Полные файлы этого шага
Следующие файлы показаны полностью. Остальные согласованные файлы находятся в том же снимке архива; переносите весь каталог при выборе исходного состояния.
notes/views.py
from django.shortcuts import render
def note_list(request):
notes = [{"title": "Расписание интервью", "body": "Согласовать вопросы к четвергу."},
{"title": "Фотография мастерской", "body": "Подобрать обложку заметки."}]
return render(request, "notes/list.html", {"notes": notes})
notes/templates/notes/list.html
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Редакционный стол</title>
</head>
<body>
<h1>Заметки редакции</h1>
{% for note in notes %}
<article>
<h2>{{ note.title }}</h2>
<p>{{ note.body }}</p>
</article>
{% empty %}
<p>Заметок пока нет.</p>
{% endfor %}
</body>
</html>
Документация и исходники
Механизм этой главы описан в официальной документации Django 5.2. При самостоятельной проверке сначала сопоставьте маршрут, представление и состояние данных, затем сравните результат с указанным ожидаемым поведением. Архив учебного проекта содержит все шестнадцать самостоятельных этапов и договор эксплуатации.