Блог на Django #12: Методы QuerySet

ORM в Django основан на QuerySet. QuerySet — это набор объектов из базы данных, который может использовать фильтры для ограничения результатов. Уже известно, как получать один объект из базы данных с помощью метода get(). Получить к нему доступ можно с помощью Post.objects.get(). Каждая модель Django имеет как минимум один менеджер, а менеджер по умолчанию называется objects. Сделать запрос к объекту (QuerySet) можно с помощью менеджера модели. Для получения всех объектов из таблицы нужно просто использовать метод all() в менеджере объектов по умолчанию:

>>> all_posts = Post.objects.all()

Таким образом можно создать QuerySet, который вернет все объекты базы данных. Но важно обратить внимание на то, что он не еще исполнился. QuerySet в Django ленивые. Они исполняются только в том случае, если их заставить. Это поведение делает инструмент крайне эффективным. Если не сохранить QuerySet в переменную, а написать его прямо в оболочку Python, выражение SQL в QuerySet исполнится автоматически, потому что такой была команда:

>>> Post.objects.all()

Метод filter()

Чтобы отфильтровать QuerySet, можно использовать метод filter() менеджера. Например, можно получить все посты за 2017 год с помощью такого запроса:

Post.objects.filter(publish__year=2017)

Можно фильтровать и по нескольким полям одновременно. Так, чтобы получить все посты за 2017 год, написанные автором admin, следует использовать команду:

Post.objects.filter(publish__year=2017, author__username='admin')

Это то же самое, что писать QuerySet с цепочкой фильтров:

Post.objects.filter(publish__year=2017) \ 
	    .filter(author__username='admin')

Запросы с методами поиска по полям пишутся с двумя нижними подчеркиваниями, например publish__year, _но такое же написание используется для получения доступа к полям связанных моделей, например author__username.

Метод exclude()

Можно исключить некоторые результаты из запроса с помощью метода менеджера exclude(). Например, можно получить все посты за 2017 год, названия которых не начинаются с Why:

Post.objects.filter(publish__year=2017) \
	    .exclude(title__startswith='Why')

Метод order_by()

Результаты можно отсортировать по полям с помощью метода менеджера order_by(). Например, можно получить все объекты, отсортированные согласно их названию (title) с помощью такой команды:

Post.objects.order_by('title')

Подразумевается расположение по возрастанию. Чтобы разместить элементы по убыванию необходимо использовать минус в качестве префикса:

Post.objects.order_by('-title')

Удаление объектов

Если нужно удалить объект, это можно сделать из экземпляра с помощью метода delete():

post = Post.objects.get(id=1) 
post.delete()

Обратите внимание, что удаление объектов также удалит все зависимые отношения для объектов ForeignKey, для которых в CASCADE определено on_delete.

Когда исполняется QuerySet

Для QuerySet можно объединить несколько фильтров, но они не коснутся базы данных, до тех пор пока QuerySet не будет выполнен. А он исполняется в следующих условиях:

  • При первой итерации по QuerySet.
  • При получении среза, например Post.objects.all()[:3].
  • При сериализации или кэшировании объектов.
  • При вызове repr() или len().
  • При прямом вызове list().
  • При проверке QuerySet в других выражениях, например bool(), or, and или if.