Ответ
Объект QuerySet в Django представляет собой коллекцию объектов из базы данных. Его ключевая особенность — ленивость (laziness): запрос к базе данных выполняется только в момент реального обращения к данным (например, в цикле или при вызове list()).
Основные методы можно разделить на две категории:
1. Методы, возвращающие новый QuerySet (не выполняют запрос к БД)
Эти методы можно выстраивать в цепочки для создания сложных запросов.
filter(**kwargs): ВозвращаетQuerySet, содержащий объекты, которые соответствуют заданным параметрам поиска.exclude(**kwargs): ВозвращаетQuerySet, исключающий объекты, которые соответствуют параметрам.order_by(*fields): СортируетQuerySetпо указанным полям. Префикс-означает сортировку по убыванию (например,'-created_at').annotate(**kwargs): Добавляет к каждому объекту вQuerySetвычисляемое поле (например, с помощью агрегатных функцийCount,Sum).values(*fields): ВозвращаетQuerySet, который при итерации выдает словари, а не объекты моделей.all(): Возвращает копию текущегоQuerySet.
2. Методы, выполняющие запрос к БД (возвращают данные)
Эти методы вызывают обращение к базе данных и возвращают конкретный результат.
get(**kwargs): Возвращает один-единственный объект. Если найдено 0 или более 1 объекта, вызывает исключение (DoesNotExistилиMultipleObjectsReturned).count(): Возвращает количество объектов вQuerySet.first()/last(): Возвращают первый/последний объект вQuerySetилиNone, если он пуст.exists(): ВозвращаетTrue, еслиQuerySetсодержит хотя бы один объект, иначеFalse. Более эффективен, чемcount() > 0.
Пример цепочки вызовов:
from django.db.models import Count
from .models import Post
# Найти 10 самых популярных постов в категории 'Python',
# опубликованных в этом году, отсортированных по количеству комментариев
popular_posts = (
Post.objects
.filter(category__name='Python', pub_date__year=2023) # Фильтрация
.annotate(num_comments=Count('comments')) # Добавление вычисляемого поля
.order_by('-num_comments') # Сортировка по убыванию
[:10] # Ограничение выборки (срез)
)
# Запрос к БД будет выполнен только здесь, при итерации
for post in popular_posts:
print(f'{post.title} - Комментариев: {post.num_comments}') Ответ 18+ 🔞
А, вот эта штука, QuerySet! Ну, слушай, это же основа основ, блядь. Представь себе, что это такой ленивый засранец, который только делает вид, что работает. Сидит, блядь, на диване, обещает тебе горы данных, а сам нихуя не делает, пока ты его реально не ткнёшь носом в результат. Ленивость, ёпта, святое дело!
Так, основные методы, они как бы на две банды делятся.
Первая банда — это те, кто только строит планы, но нихуя не делает.
Типа, filter() — отберёт тебе только то, что нужно. exclude() — наоборот, выкинет всё лишнее, как говно из ванны. order_by() — расставит всё по полочкам, по алфавиту или наоборот, если поставишь минус. annotate() — это вообще хитрая жопа, она каждому объекту новые поля пририсует, типа «а вот смотри, у этого поста сколько там комментариев». И всё это можно в цепочку собирать, как паровозик, и они будут друг другу кивать: «Ага, понял, отфильтрую, потом отсортирую, потом посчитаю». А запрос в базу? Нихуя! Пока не спросишь по-взрослому.
Вторая банда — это те, кто сразу лезет в драку.
Вот get() — это такой отчаянный мудак, который ищет ОДИН объект. Найдёт — молодец. Не найдёт — орёт «DoesNotExist!». Найдёт два — орет «MultipleObjectsReturned!». Пиздец просто.
count() — посчитает, сколько всего. first() и last() — вытащат первого и последнего, если есть. А exists() — это вообще гениально, он просто смотрит, есть хоть что-то или нет, и говорит «да» или «нет». Быстрее, чем считать всё дохуя, честно.
Вот смотри, как это в жизни выглядит, на примере блога:
from django.db.models import Count
from .models import Post
# Хотим найти 10 самых популярных постов про Python за этот год
popular_posts = (
Post.objects
.filter(category__name='Python', pub_date__year=2023) # Отфильтровали
.annotate(num_comments=Count('comments')) # Присобачили к каждому счётчик комментариев
.order_by('-num_comments') # Отсортировали по убыванию, чтобы самые болтливые сверху
[:10] # Отрезали топ-10, как торт
)
# И вот тут, сука, только сейчас этот ленивый уёбок полезет в базу данных!
# Когда ты начнёшь по этому списку итерироваться.
for post in popular_posts:
print(f'{post.title} - Комментариев: {post.num_comments}')
Вот и вся магия. Сначала накручиваешь условия, как на ёлку гирлянды, а потом — раз! — и включаешь. И если что-то пошло не так, всегда можно крикнуть: «Да что ж ты, блядь, get()-то вызвал, когда их там три штуки?!».