Какие основные методы Django QuerySet используются для получения и фильтрации данных?

Ответ

Объект 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}')