Django ORM, методы которые не возвращают QuerySet

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

Методы, выполняющие запрос сразу

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

Получение одного объекта

Book.objects.get(pk=1)              # ровно один или исключение
Book.objects.first()                # первый (по сортировке) или None
Book.objects.last()                 # последний или None
Post.objects.latest("publish")      # самый поздний по полю
Post.objects.earliest("publish")    # самый ранний

get() выбрасывает DoesNotExist или MultipleObjectsReturned. first()/last() возвращают None — удобно, когда объекта может не быть:

book = Book.objects.filter(title__icontains="война").first()
if book:
    ...

Создание и обновление

Book.objects.create(title="Нос", author=gogol)

get_or_create

Найти, а если нет — создать. Возвращает кортеж (объект, создан_ли):

tag, created = Tag.objects.get_or_create(name="django")
if created:
    print("Новый тег")

Поля для создания, которые не участвуют в поиске, передают в defaults:

author, created = Author.objects.get_or_create(
    name="Гоголь",
    defaults={"country": "Россия"},
)

update_or_create

Найти и обновить, а если нет — создать:

Book.objects.update_or_create(
    title="Мёртвые души",
    defaults={"pages": 352, "author": gogol},
)

Эту пару методов использует загрузчик курсов этого сайта: при повторном запуске load_courses уроки обновляются, а не дублируются.

bulk_create и bulk_update

Book.objects.bulk_create([Book(title=f"Том {i}", author=gogol) for i in range(1, 6)])

books = list(Book.objects.filter(author=gogol))
for b in books:
    b.pages += 10
Book.objects.bulk_update(books, ["pages"])

Один запрос вместо десятков. Но save() и сигналы не вызываются.

Подсчёт и проверка

Book.objects.count()                      # SELECT COUNT(*)
Book.objects.filter(pages__gt=500).exists()  # True / False

count() или len()?

len(qs) загрузит все объекты в память и посчитает их в Python. qs.count() посчитает в базе. Но если вы всё равно будете перебирать объекты — len() не сделает лишнего запроса.

Агрегация: aggregate()

aggregate считает итог по всему набору и возвращает словарь:

from django.db.models import Avg, Count, Max, Min, Sum

Book.objects.aggregate(Avg("pages"))
# {'pages__avg': 512.4}

Book.objects.aggregate(avg=Avg("pages"), total=Sum("pages"), longest=Max("pages"))
# {'avg': 512.4, 'total': 25620, 'longest': 1300}

Сравните с annotate из прошлого урока: annotate добавляет значение каждому объекту, aggregate — одно значение на весь набор.

Массовые изменения

Book.objects.filter(author=gogol).update(pages=0)   # вернёт число изменённых строк
Book.objects.filter(pages=0).delete()               # вернёт (число, {модель: число})

Чтобы обновить значение относительно текущего, используют F-выражения:

from django.db.models import F

Post.objects.filter(pk=1).update(views=F("views") + 1)   # атомарно, без гонок

Словарь по ключам: in_bulk()

Book.objects.in_bulk([1, 2, 3])
# {1: <Book: ...>, 2: <Book: ...>, 3: <Book: ...>}
Book.objects.in_bulk(["nos", "shinel"], field_name="slug")

Большие объёмы: iterator()

for book in Book.objects.iterator(chunk_size=2000):
    process(book)

Объекты читаются порциями и не кэшируются — экономия памяти при обработке миллионов строк.

Сводная таблица

Метод Возвращает
get() объект или исключение
first(), last() объект или None
latest(), earliest() объект или исключение
create() созданный объект
get_or_create(), update_or_create() (объект, created)
bulk_create() список объектов
count() число
exists() True / False
aggregate() словарь
update() число строк
delete() кортеж с количеством
in_bulk() словарь
iterator() итератор

Итог

  • Эти методы выполняют запрос сразу и возвращают не QuerySet.
  • get_or_create и update_or_create избавляют от проверок «есть ли уже такой объект».
  • exists() и count() выполняются в базе — эффективнее, чем загрузка объектов.
  • aggregate — итог по набору, F — ссылка на значение поля в базе.

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

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

Как эффективнее всего проверить, есть ли у автора хотя бы одна книга?

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

Получите тег с именем django, а если его нет — создайте. Распакуйте результат в переменные tag и created.

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

Посчитайте среднее и максимальное число страниц среди всех книг одним запросом. Результат (словарь) сохраните в stats, ключи — avg_pages и max_pages.

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

Что вернёт Book.objects.filter(pages__gt=5000).first(), если таких книг нет?

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

Какие методы не вызывают save() у каждой модели и не отправляют сигналы pre_save/post_save?

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

Какой метод вернёт самый свежий пост по полю publish? Напишите вызов целиком: Post.objects.???

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