Назовите основные методы Django ORM для выборки и фильтрации данных

Ответ

Django ORM предоставляет мощный API для взаимодействия с базой данных через объекты QuerySet. Ключевая особенность QuerySetленивость (laziness): запрос к БД выполняется только в момент реального обращения к данным.

Методы делятся на две основные группы:

1. Методы, возвращающие новый QuerySet (ленивые)

Эти методы можно выстраивать в цепочки, уточняя запрос.

  • `filter(kwargs)**: Фильтрует записи по заданным условиям (эквивалентWHERE`).
  • `exclude(kwargs)`**: Исключает записи, соответствующие условиям.
  • *`order_by(fields)**: Сортирует результат (эквивалентORDER BY`).
  • `annotate(kwargs)**: Добавляет к каждому объекту вQuerySet` вычисляемое поле (например, с помощью агрегатных функций).
  • *`values(fields)**: ВозвращаетQuerySet` словарей вместо объектов модели, что может быть эффективнее.
  • *`select_related(fields)**: Оптимизирует запросы, "подтягивая" связанные объекты поForeignKeyилиOneToOneFieldодним SQL-запросом (делаетJOIN`).
  • *`prefetch_related(lookups)**: Оптимизирует запросы дляManyToManyFieldи обратныхForeignKey`, выполняя отдельный запрос для связанных объектов и объединяя их в Python.

2. Методы, выполняющие запрос к БД (терминальные)

Эти методы заставляют QuerySet выполнить запрос к базе данных и вернуть результат.

  • `get(kwargs)**: Возвращает один-единственный объект. Вызывает исключениеDoesNotExistилиMultipleObjectsReturned`, если объект не найден или найдено несколько.
  • all(): Возвращает копию текущего QuerySet (часто используется как начальная точка).
  • count(): Возвращает количество объектов в QuerySet (выполняет SELECT COUNT(*)).
  • first() / last(): Возвращают первый/последний объект после сортировки.
  • exists(): Возвращает True или False, проверяя, содержит ли QuerySet хотя бы один объект. Эффективнее, чем count() > 0.

Пример комплексного запроса:

from django.db.models import Count

# Найти 5 самых популярных категорий (с наибольшим количеством активных постов),
# исключая одну конкретную категорию.

top_categories = Category.objects.filter(
    post__is_active=True  # Фильтруем по полю связанной модели
).exclude(
    name='Архив' # Исключаем категорию 'Архив'
).annotate(
    num_posts=Count('post')  # Добавляем вычисляемое поле с количеством постов
).order_by(
    '-num_posts'  # Сортируем по убыванию количества постов
)[:5]  # Выполняем запрос и берем срез из первых 5 результатов