Первые ORM запросы (CRUD)

⏱ 25 мин · 🧩 заданий: 7

ORM: Python вместо SQL

ORM (Object-Relational Mapping) переводит работу с объектами Python в SQL-запросы. Вместо

SELECT * FROM library_book WHERE author = 'Толстой';

вы пишете

Book.objects.filter(author="Толстой")

Плюсы: не нужно писать SQL, код не зависит от конкретной СУБД, защита от SQL-инъекций встроена.

Django shell

Экспериментировать с ORM удобно в консоли:

python manage.py shell
>>> from library.models import Book
>>> Book.objects.all()
<QuerySet []>

С Django 5.2 модели всех приложений импортируются в shell автоматически.

Менеджер objects

У каждой модели есть менеджер objects — точка входа для запросов. Он возвращает QuerySet — «ленивый» набор объектов из базы.

Create — создание

Способ 1: создать объект и сохранить.

book = Book(title="Война и мир", author="Толстой", pages=1300)
book.save()          # INSERT
print(book.id)       # id появился после сохранения

Способ 2: одной командой.

book = Book.objects.create(title="Анна Каренина", author="Толстой", pages=860)

Массово:

Book.objects.bulk_create([
    Book(title="Отцы и дети", author="Тургенев", pages=290),
    Book(title="Муму", author="Тургенев", pages=40),
])

Read — чтение

Book.objects.all()                       # все книги
Book.objects.filter(author="Толстой")    # с условием
Book.objects.exclude(author="Толстой")   # все, кроме
Book.objects.get(pk=1)                   # ровно один объект
Book.objects.filter(author="Толстой").first()  # первый или None
Book.objects.count()                     # количество
Book.objects.order_by("-pages")          # сортировка
Book.objects.all()[:5]                   # первые 5 (LIMIT 5)

get() и исключения

get() ожидает ровно один результат:

try:
    book = Book.objects.get(pk=100)
except Book.DoesNotExist:
    book = None

Во view для этого есть сокращение get_object_or_404(Book, pk=100) — вернёт объект или страницу 404.

Цепочки и условия

Методы QuerySet можно соединять в цепочки:

Book.objects.filter(author="Толстой").exclude(pages__lt=500).order_by("title")

pages__lt — поисковое выражение (lookup): двойное подчёркивание + оператор. Основные:

Lookup Значение SQL
pages__gt=100 больше > 100
pages__gte=100 больше или равно >= 100
pages__lt=100 меньше < 100
title__contains="мир" содержит LIKE '%мир%'
title__icontains="мир" содержит, без учёта регистра
title__startswith="А" начинается с LIKE 'А%'
author__in=["Толстой", "Чехов"] одно из IN (...)
published__year=2020 год даты

Подробнее о lookups — в отдельном уроке модуля.

Ленивость

QuerySet не обращается к базе, пока данные действительно не понадобятся (цикл, list(), срез с шагом, len(), вывод в шаблоне). Поэтому цепочки фильтров — это один запрос, а не несколько.

qs = Book.objects.filter(author="Толстой")  # запроса ещё нет
qs = qs.order_by("title")                   # всё ещё нет
for book in qs:                             # вот теперь — один SELECT
    print(book.title)

Update — изменение

Одного объекта:

book = Book.objects.get(pk=1)
book.pages = 1274
book.save()                         # UPDATE всех полей
book.save(update_fields=["pages"])  # UPDATE только pages

Многих сразу — одним запросом:

Book.objects.filter(author="Толстой").update(author="Л. Н. Толстой")

Delete — удаление

book = Book.objects.get(pk=1)
book.delete()

Book.objects.filter(pages=0).delete()   # удалить все подходящие

Осторожно

Book.objects.all().delete() удалит все книги. Django не переспрашивает.

Посмотреть SQL

qs = Book.objects.filter(author="Толстой")
print(qs.query)

Полезно, чтобы понимать, что именно делает ORM.

Итог

  • objects — менеджер, возвращающий QuerySet.
  • Create: create(), save(), bulk_create().
  • Read: all(), filter(), exclude(), get(), first(), count(), order_by().
  • Update: изменить атрибут + save() или QuerySet.update().
  • Delete: obj.delete() или QuerySet.delete().
  • QuerySet ленивый: запрос выполняется при обращении к данным.

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

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

Создайте и сохраните в базе книгу с названием Мастер и Маргарита и автором Булгаков одной командой через менеджер objects. Результат сохраните в переменную book.

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

Что произойдёт, если Book.objects.get(pk=100) не найдёт книгу?

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

Получите QuerySet всех книг автора Толстой, кроме тех, у которых меньше 100 страниц (поле pages). Используйте filter и exclude, результат — в переменную books.

Задание 4 Расставить по порядку

Расставьте шаги, чтобы изменить название книги с id=3.

  1. book.save()
  2. book.title = "Новое название"
  3. book = Book.objects.get(pk=3)
Задание 5 Один вариант ответа

Чем Book.objects.filter(pages=0).update(pages=1) лучше цикла с save() для каждой книги?

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

Какой командой открыть интерактивную консоль Python с подключённым проектом Django?

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

Найдите книгу по pk=5 и удалите её.

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