Перейти к содержанию

Django ORM: выборка и порядок заметок

Оглавление курса · Скачать все состояния проекта.

Учебная задача: Заменить временные данные QuerySet и объяснить момент получения строк из базы.

Входное состояние: Снимок lesson-05: модель и начальная миграция; список получает словари. Выходное состояние: Список получает QuerySet модели Note, доступны учебные fixtures и определённый порядок. Эта глава продолжает «Редакционный стол» — небольшой сайт заметок. Нужны основы Python, HTML и устройство HTTP-запроса. Используем Python 3.12 и Django 5.2.18 LTS; номер ветки выбран для этой серии. Полный каталог lesson-06 в архиве содержит собственные настройки, шаблоны и историю миграций. При самостоятельном прохождении выберите один снимок и отдельную локальную базу; смешивание файлов разных глав меняет договор примера.

Исходники подготовлены редакционным чтением. Зависимости, миграции, сервер и команды работы с данными здесь не выполнялись. Все описанные ответы и изменения являются ожидаемыми, example_execution: not_run.

Модель Note уже описывает хранение данных. Теперь переключим список с временных словарей на ORM — средства Django для построения запросов к базе через Python. Оболочка и шаблон сохраняются. Представление начинает выбирать записи модели и передавать их под прежним именем notes. Такой переход удобен для обучения: он меняет именно источник данных, поэтому результат можно объяснить без одновременной переработки всей страницы.

QuerySet представляет выборку, описанную условиями и порядком. Это не обязательно уже готовый список объектов в памяти. Многие операции создают новый QuerySet, а получение строк откладывается до момента, когда данные действительно нужны. Шаблон начинает обходить коллекцию, и тогда запрос должен быть выполнен. Поэтому наличие переменной notes в функции ещё не означает, что все строки уже прочитаны. Важно различать построение запроса и его оценку.

Менеджер и операции выборки

У Note есть стандартный менеджер objects. Через него вызываются all, filter, get и другие операции работы с записями. В нашем представлении используем явный order_by("-created_at", "-pk"). Минус перед именем поля означает убывание. Новые заметки оказываются выше старых, а первичный ключ уточняет порядок при совпадении времени. Это тот же договор, который ранее записали в Meta; явная операция позволяет увидеть его непосредственно у источника страницы.

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

filter возвращает коллекцию, даже если подходящих объектов нет. get ожидает один объект и иначе сообщает об отсутствии или нескольких совпадениях. Для списка естественна коллекция. Для карточки позднее удобно использовать get_object_or_404, который переводит отсутствие записи в HTTP-результат. Не применяйте get вместо filter только потому, что сейчас в базе одна строка: форма результата должна соответствовать смыслу операции, а не случайному количеству данных.

Один шаблон для нового источника

В цикле шаблона прежнее выражение note.title теперь читает атрибут экземпляра модели. Для HTML несущественно, был ли этот заголовок получен из словаря или модели, если имя и значение согласованы. Такой подход называют разделением представления и источника данных. Он не требует особой абстракции на каждом шаге. Достаточно не привязывать HTML к внутренним подробностям соединения с базой.

При пустой таблице QuerySet будет пустым и сработает ветка empty. Не добавляйте фиктивную заметку из кода только ради того, чтобы всегда видеть красивую карточку. Пустое состояние является нормальной частью интерфейса. Вместо этого для самостоятельного знакомства есть fixtures — отдельный JSON с двумя учебными записями. Он явно задаёт модель, ключи и значения, не содержит личных данных и не утверждает, что база уже была заполнена при подготовке урока.

Команда loaddata editorial может загрузить fixture после применения миграций в выбранном снимке. Это инструкция для читателя, а не выполненная здесь операция. Fixture относится к текущей схеме: в следующих снимках добавятся slug, статус и обложка. Не загружайте поздний файл в раннюю схему, если он содержит ещё неизвестные поля. Согласованность данных и миграций так же важна, как согласованность импорта модели.

Ленивость и лишние обращения

Если вы начнёте запрашивать связанные объекты внутри каждого элемента, число обращений к базе может расти вместе с длиной списка. В нашем случае связей пока нет, поэтому такого эффекта ещё не возникает. Тем не менее запомните место будущей проблемы: шаблон визуально показывает один список, но его выражения способны получать дополнительные данные. Позднее связь автора можно заранее прочитать через select_related, когда это действительно понадобится.

Не превращайте QuerySet в list без причины. Такое преобразование немедленно получает все элементы и занимает память под них. Для небольшой редакционной подборки разница может быть незаметна, но привычка влияет на более крупные экраны. Также не используйте длину всей коллекции для задачи, которая просит только факт существования. ORM предоставляет операции вроде exists; выбирать следует по требуемому результату, а не по знакомому синтаксису.

После самостоятельной загрузки исходных данных ожидается, что «Фотография мастерской» отображается первой: её дата позже. Заголовок и текст каждой записи должны остаться связаны. Если таблица пуста, ожидается сообщение пустого состояния. Если миграция не применена, возможна ошибка отсутствующей таблицы, и это не тот же результат, что пустая выборка. Объясните эти три случая до перехода к административной панели. В следующей главе редактор сможет создавать данные через готовый внутренний интерфейс Django.

Разбор связи файлов

Запрос без подходящих строк остаётся корректным QuerySet. Это отличается от операции get, которая требует ровно один объект и иначе сообщает об отсутствии либо множественности. Выбирайте форму операции по смыслу: страница списка допускает любое число элементов, карточка ожидает один определённый материал. Превращать каждое отсутствие в технический сбой списка не нужно.

Фикстура фиксирует учебные записи и их первичные ключи. Она помогает получить одинаковый исходный набор, но не является механизмом заполнения любой существующей редакции. Повторная загрузка в базу с реальными данными требует понимания последствий. В архиве приведено назначение команды для отдельной локальной базы; здесь не утверждается, что данные уже загружены.

Когда шаблон начинает обходить QuerySet, ленивый запрос получает необходимость выполнения. Поэтому объявление переменной в представлении и обращение к результату во время рендеринга — разные моменты. Для данного маленького списка не нужна преждевременная сложная оптимизация, но полезно понимать причину появления запроса. Если позже каждая заметка потребует автора, отдельно рассмотрим связанные объекты; один QuerySet не гарантирует отсутствие всех дополнительных обращений к базе.

Полные файлы этого шага

Следующие файлы показаны полностью. Остальные согласованные файлы находятся в том же снимке архива; переносите весь каталог при выборе исходного состояния.

notes/views.py

from django.shortcuts import render
from .models import Note

def note_list(request):
    notes = Note.objects.order_by("-created_at", "-pk")
    return render(request, "notes/list.html", {"notes": notes})

notes/fixtures/editorial.json

[
  {
    "model": "notes.note",
    "pk": 1,
    "fields": {
      "title": "Расписание интервью",
      "body": "Согласовать вопросы к четвергу.",
      "created_at": "2026-10-01T09:00:00Z"
    }
  },
  {
    "model": "notes.note",
    "pk": 2,
    "fields": {
      "title": "Фотография мастерской",
      "body": "Подобрать обложку заметки.",
      "created_at": "2026-10-02T09:00:00Z"
    }
  }
]

Документация и исходники

Механизм этой главы описан в официальной документации Django 5.2. При самостоятельной проверке сначала сопоставьте маршрут, представление и состояние данных, затем сравните результат с указанным ожидаемым поведением. Архив учебного проекта содержит все шестнадцать самостоятельных этапов и договор эксплуатации.