Spec-Zone.ru › Django 4.1

Справочник по API QuerySet

В данном документе описываются подробности API QuerySet. Он основан на материалах, представленных в руководствах по моделям и запросам к базе данных, поэтому, вероятно, вам следует прочитать и понять эти документы перед чтением данного.

В этом справочнике мы будем использовать пример моделей блога, представленных в руководстве по запросам к базе данных.

Когда QuerySet вычисляются

Внутри, QuerySet может быть создан, отфильтрован, разбит на части и, в общем, передан без фактического обращения к базе данных. Никакая активность базы данных не происходит до тех пор, пока вы не выполните какое-либо действие для вычисления QuerySet.

Вы можете вычислить QuerySet следующими способами:

  • Итерация. QuerySet итерируемый, и он выполняет свой запрос к базе данных в первый раз, когда вы итерируетесь по нему. Например, это выведет заголовок всех записей в базе данных:

    for e in Entry.objects.all():
        print(e.headline)
    

    Примечание: Не используйте это, если все, что вам нужно, это определить, существует ли хотя бы один результат. Более эффективно использовать exists().

  • Асинхронная итерация.. QuerySet также можно итерировать с помощью async for:

    async for e in Entry.objects.all():
      results.append(e)
    

    Синхронные и асинхронные итераторы QuerySet используют один и тот же кэш.

    Изменено в Django 4.1:

    Добавлена поддержка асинхронной итерации.

  • Разбиение на части. Как объясняется в Ограничение QuerySet, QuerySet можно разбить на части, используя синтаксис разбиения массивов Python. Разбиение невычисленного QuerySet обычно возвращает другой невычисленный QuerySet, но Django выполнит запрос к базе данных, если вы используете параметр «шаг» синтаксиса разбиения, и вернёт список. Разбиение вычисленного QuerySet также возвращает список.

    Также обратите внимание, что, хотя разбиение невычисленного QuerySet возвращает другой невычисленный QuerySet, дальнейшее его изменение (например, добавление дополнительных фильтров или изменение сортировки) не допускается, так как это не переводится в SQL и не имеет ясного смысла.

  • Сериализация/Кеширование. Подробности о том, что происходит при сериализации QuerySet, см. в следующем разделе. Важно, что результаты считываются из базы данных.
  • repr(). QuerySet вычисляется при вызове repr() на нём. Это делается для удобства в интерактивном интерпретаторе Python, чтобы вы сразу могли видеть результаты при интерактивном использовании API.
  • len(). QuerySet вычисляется при вызове len() на нём. Это, как можно предположить, возвращает длину списка результатов.

    Примечание: Если вам нужно только определить количество записей в наборе (и вам не нужны сами объекты), гораздо эффективнее обработать подсчёт на уровне базы данных с помощью SQL SELECT COUNT(*). Django предоставляет метод count() именно по этой причине.

  • list(). Вынужденное вычисление QuerySet вызовом list() на нём. Например:

    entry_list = list(Entry.objects.all())
    
  • bool(). Проверка QuerySet в контексте булевой переменной, например, используя bool(), or, and или оператор if, вызовет выполнение запроса. Если существует хотя бы один результат, QuerySet True, в противном случае False. Например:

    if Entry.objects.filter(headline="Test"):
       print("There is at least one Entry with the headline Test")
    

    Примечание: Если вам нужно только определить, существует ли хотя бы один результат (и вам не нужны сами объекты), более эффективно использовать exists().

Сериализация QuerySet

Если вы pickle QuerySet, это принудительно загрузит все результаты в память перед сериализацией. Сериализация обычно используется в качестве прекурсора к кешированию, и когда кэшированный QuerySet перезагружается, вы хотите, чтобы результаты уже были доступны и готовы к использованию (чтение из базы данных может занять некоторое время, что сведёт на нет цель кеширования). Это означает, что когда вы десериализуете QuerySet, он содержит результаты на момент сериализации, а не результаты, которые в настоящее время находятся в базе данных.

Если вы хотите сериализовать только необходимую информацию для восстановления QuerySet из базы данных в будущем, сериализуйте атрибут query QuerySet . Затем вы можете восстановить исходный QuerySet (без загруженных результатов) с помощью кода, подобного этому:

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

Атрибут query — это непрозрачный объект. Он представляет внутреннее состояние построения запроса и не является частью публичного API. Тем не менее, безопасно (и полностью поддерживается) сериализовать и десериализовать содержимое атрибута, как описано здесь.

Ограничения на QuerySet.values_list()

Если вы восстанавливаете QuerySet.values_list() с использованием сериализованного атрибута query, он будет преобразован в QuerySet.values():

>>> import pickle
>>> qs = Blog.objects.values_list('id', 'name')
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

Сериализованные объекты нельзя использовать между версиями

Сериализованные объекты QuerySets действительны только для версии Django, которая использовалась для их создания. Если вы создали сериализованный объект с помощью версии Django N, нет гарантии, что он будет читаем с версией Django N+1. Сериализованные объекты не следует использовать в стратегии долговременного архивирования.

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

QuerySet API

Вот формальное объявление QuerySet:

class QuerySet(model=None, query=None, using=None, hints=None)

Обычно при взаимодействии с QuerySet вы используете его, цепляя фильтры. Для того, чтобы это работало, большинство методов QuerySet возвращают новые QuerySet. Эти методы подробно рассматриваются позже в этом разделе.

Класс QuerySet имеет следующие общедоступные атрибуты, которые вы можете использовать для интроспекции:

ordered

True если QuerySet отсортирован — т. е. имеет пункт order_by() или стандартную сортировку модели. False в противном случае.

db

База данных, которая будет использована, если этот запрос будет выполнен сейчас.

Примечание

Параметр query для QuerySet существует для того, чтобы специализированные подклассы запросов могли восстановить внутреннее состояние запроса. Значение параметра — это непрозрачное представление этого состояния запроса и не является частью публичного API.

Методы, которые возвращают новые QuerySet

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

Примечание

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

filter()

filter(*args, **kwargs)

Возвращает новый QuerySet, содержащий объекты, соответствующие заданным параметрам поиска.

Параметры поиска (**kwargs) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются с помощью AND в базовом операторе SQL.

Если вам нужно выполнить более сложные запросы (например, запросы с операторами OR ), вы можете использовать Q objects (*args).

exclude()

exclude(*args, **kwargs)

Возвращает новый QuerySet, содержащий объекты, которые не соответствуют заданным параметрам поиска.

Параметры поиска (**kwargs) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются с помощью AND в базовом операторе SQL, и всё это заключено в NOT().

В этом примере исключаются все записи, у которых pub_date позднее 2005-01-03 И у которых headline равно «Hello»:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

В терминах SQL это оценивается как:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

В этом примере исключаются все записи, у которых pub_date позднее 2005-01-03 ИЛИ у которых заголовок «Hello»:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

В терминах SQL это оценивается как:

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

Обратите внимание, что второй пример более ограничителен.

Если вам нужно выполнить более сложные запросы (например, запросы с OR операторами), вы можете использовать Q objects (*args).

annotate()

annotate(*args, **kwargs)

Добавляет к каждому объекту в QuerySet указанный список выражений запроса. Выражение может быть простым значением, ссылкой на поле модели (или любой связанной модели) или агрегированным выражением (среднее значение, сумма и т. д.), вычисленным для объектов, связанных с объектами в QuerySet.

Каждый аргумент к annotate() представляет собой аннотацию, которая будет добавлена к каждому объекту в QuerySet , который возвращается.

Функции агрегирования, которые предоставляются Django, описаны в Функциях агрегирования ниже.

Аннотации, указанные с помощью именованных аргументов, будут использовать имя аргумента в качестве псевдонима аннотации. Анонимные аргументы будут иметь псевдоним, сгенерированный на основе имени функции агрегирования и поля модели, которое агрегируется. Только агрегированные выражения, ссылающиеся на одно поле, могут быть анонимными аргументами. Все остальное должно быть именованным аргументом.

Например, если вы работаете со списком блогов, вы можете захотеть определить, сколько записей было сделано в каждом блоге:

>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

Модель Blog не определяет атрибут entry__count сама по себе, но с помощью именованного аргумента для указания функции агрегирования вы можете контролировать имя аннотации:

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42

Для углубленного обсуждения агрегирования см. руководство по теме Агрегирования.

alias()

alias(*args, **kwargs)

То же, что и annotate(), но вместо аннотирования объектов в QuerySet, сохраняет выражение для последующего использования с другими QuerySet методами. Это полезно, когда результат выражения сам по себе не нужен, но используется для фильтрации, сортировки или в качестве части сложного выражения. Невыборка неиспользуемого значения удаляет излишнюю работу из базы данных, что должно привести к лучшей производительности.

Например, если вы хотите найти блоги с более чем 5 записями, но не заинтересованы в точном количестве записей, вы можете сделать это:

>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count('entry')).filter(entries__gt=5)

alias() можно использовать вместе с annotate(), exclude(), filter(), order_by() и update(). Чтобы использовать алиасованные выражения с другими методами (например, aggregate()), вы должны преобразовать его в аннотацию:

Blog.objects.alias(entries=Count('entry')).annotate(
    entries=F('entries'),
).aggregate(Sum('entries'))

filter() и order_by() могут принимать выражения непосредственно, но построение выражений и их использование часто не происходит в одном месте (например, метод QuerySet создает выражения для последующего использования в представлениях). alias() позволяет наращивать сложные выражения по частям, возможно, охватывая несколько методов и модулей, ссылаясь на части выражения по их псевдонимам и используя только annotate() для конечного результата.

order_by()

order_by(*fields)

По умолчанию результаты, возвращаемые QuerySet, сортируются по кортежу сортировки, заданному опцией ordering в Meta модели. Вы можете переопределить это для каждого QuerySet с помощью метода order_by.

Пример:

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

Результат выше будет отсортирован по pub_date по убыванию, затем по headline по возрастанию. Минус перед "-pub_date" указывает на сортировку по убыванию. Возрастающая сортировка подразумевается. Для случайной сортировки используйте "?", как показано ниже:

Entry.objects.order_by('?')

Примечание: Запросы с order_by('?') могут быть дорогими и медленными, в зависимости от используемого вами движка базы данных.

Чтобы отсортировать по полю в другой модели, используйте ту же синтаксическую конструкцию, что и при запросе через отношения моделей. То есть, имя поля, за которым следует двойное подчеркивание (__), а затем имя поля в новой модели, и так далее для всех необходимых моделей. Например:

Entry.objects.order_by('blog__name', 'headline')

Если вы пытаетесь отсортировать по полю, которое является отношением к другой модели, Django будет использовать стандартную сортировку связанной модели или сортировать по первичному ключу связанной модели, если опция Meta.ordering не указана. Например, поскольку в модели Blog нет заданной сортировки по умолчанию:

Entry.objects.order_by('blog')

…эквивалентно:

Entry.objects.order_by('blog__id')

Если бы Blog имела ordering = ['name'], то первый запрос был бы идентичен:

Entry.objects.order_by('blog__name')

Вы также можете сортировать по выражениям запроса, вызвав asc() или desc() для выражения:

Entry.objects.order_by(Coalesce('summary', 'headline').desc())

asc() и desc() имеют аргументы (nulls_first и nulls_last) для управления тем, как сортируются нулевые значения.

Будьте осторожны при сортировке по полям связанных моделей, если вы также используете distinct(). Обратитесь к примечанию в distinct() для объяснения того, как сортировка по связанным моделям может изменить ожидаемые результаты.

Примечание

Разрешается указать многозначное поле для сортировки результатов (например, поле ManyToManyField или обратное отношение поля ForeignKey).

Рассмотрим этот случай:

class Event(Model):
   parent = models.ForeignKey(
       'self',
       on_delete=models.CASCADE,
       related_name='children',
   )
   date = models.DateField()

Event.objects.order_by('children__date')

В этом случае потенциально может быть несколько данных для сортировки для каждого Event; каждый Event с несколькими children будет возвращен несколько раз в новый QuerySet , который создает order_by(). Другими словами, использование order_by() по QuerySet может вернуть больше элементов, чем вы изначально обрабатывали — что, скорее всего, не ожидается и не полезно.

Поэтому будьте осторожны при использовании многозначных полей для сортировки результатов. **Если** вы уверены, что для каждого элемента, который вы сортируете, будет только одно значение для сортировки, то этот подход не должен вызывать проблем. Если нет, убедитесь, что результаты соответствуют вашим ожиданиям.

Нет способа указать, должна ли сортировка быть регистрозависимой. В отношении регистрозависимости Django отсортирует результаты так, как это обычно делает ваша база данных.

Вы можете сортировать по полю, преобразованному в нижний регистр с помощью Lower, чтобы обеспечить согласованную сортировку с учетом регистра:

Entry.objects.order_by(Lower('headline').desc())

Если вы не хотите, чтобы для запроса применялась никакая сортировка, даже сортировка по умолчанию, вызовите order_by() без параметров.

Вы можете узнать, отсортирован ли запрос или нет, проверив атрибут QuerySet.ordered, который будет True , если запрос был отсортирован каким-либо образом.

Каждый вызов order_by() очистит все предыдущие сортировки. Например, этот запрос будет отсортирован по pub_date , а не по headline:

Entry.objects.order_by('headline').order_by('pub_date')

Предупреждение

Сортировка не является бесплатной операцией. Каждый добавленный вами столбец в сортировке влечёт за собой затраты на вашу базу данных. Каждый внешний ключ также подразумевает включение всех его стандартных сортировок.

Если в запросе не указана сортировка, результаты возвращаются из базы данных в неуказанном порядке. Гарантируется определенная сортировка только при сортировке по набору полей, уникально идентифицирующих каждый объект в результатах. Например, если поле name не уникально, сортировка по нему не гарантирует, что объекты с одинаковым именем всегда будут отображаться в одинаковом порядке.

reverse()

reverse()

Используйте метод reverse() для изменения порядка возвращаемых элементов набора запросов. Вызов reverse() второй раз восстанавливает порядок обратно к исходному направлению.

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

my_queryset.reverse()[:5]

Обратите внимание, что это не совсем то же самое, что срезы с конца последовательности в Python. В приведённом выше примере будет возвращён последний элемент, затем предпоследний и так далее. Если бы у нас была последовательность Python и мы посмотрели бы на seq[-5:], мы бы увидели пятый с конца элемент первым. Django не поддерживает этот режим доступа (срез с конца), потому что его невозможно эффективно реализовать в SQL.

Также обратите внимание, что reverse() в целом следует вызывать только на наборе запросов QuerySet, имеющем определённую сортировку (например, при запросе к модели, которая определяет стандартную сортировку, или при использовании order_by()). Если для данного набора запросов QuerySet такая сортировка не определена, вызов reverse() на нём не оказывает реального влияния (сортировка была неопределённой до вызова reverse(), и останется неопределённой после).

distinct()

distinct(*fields)

Возвращает новый набор запросов QuerySet, который использует SELECT DISTINCT в запросе SQL. Это устраняет дублирующиеся строки из результатов запроса.

По умолчанию набор запросов QuerySet не удаляет дублирующиеся строки. На практике это редко является проблемой, потому что простые запросы, такие как Blog.objects.all() , не создают возможности дублирования результатов запроса. Однако если ваш запрос охватывает несколько таблиц, могут появиться дублирующие результаты при оценке набора запросов QuerySet. Именно тогда используется distinct().

Примечание

Любые поля, используемые в вызове order_by(), включаются в SQL столбцы SELECT. Это иногда может привести к непредсказуемым результатам при использовании в сочетании с distinct(). Если вы сортируете по полям из связанной модели, эти поля будут добавлены в выбранные столбцы, и они могут заставить строки, которые в противном случае были бы дублирующими, выглядеть отличными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они нужны только для поддержки сортировки), иногда кажется, что возвращаются не дубликаты.

Аналогично, если вы используете запрос values() для ограничения выбираемых столбцов, столбцы, используемые в любом вызове order_by() (или стандартной сортировке модели), всё ещё будут задействованы и могут повлиять на уникальность результатов.

Вывод: если вы используете distinct(), будьте осторожны при сортировке по связанным моделям. Аналогично, при совместном использовании distinct() и values(), будьте осторожны при сортировке по полям, не включённым в вызов values().

Только в PostgreSQL вы можете передавать позиционные аргументы (*fields) для указания имён полей, к которым следует применить DISTINCT. Это приводит к запросу SQL SELECT DISTINCT ON. Вот разница. При обычном вызове distinct(), база данных сравнивает каждое поле в каждой строке при определении уникальности строк. Для вызова distinct() с указанием имён полей база данных будет сравнивать только указанные имена полей.

Примечание

Когда вы указываете имена полей, вы обязательно должны предоставить порядок order_by() в QuerySet, и поля в order_by() должны начинаться с полей в distinct(), в том же порядке.

Например, SELECT DISTINCT ON (a) даёт вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите произвольную строку.

Примеры (те, что после первого, будут работать только в PostgreSQL):

>>> Author.objects.distinct()
[...]

>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]

>>> Entry.objects.order_by('blog').distinct('blog')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]

>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]

Примечание

Заметьте, что order_by() использует любые стандартные сортировки связанных моделей, которые были определены. Возможно, вам придётся явно указать сортировку по отношению _id или ссылаемому полю, чтобы убедиться, что выражения DISTINCT ON соответствуют тем, которые находятся в начале фрагмента ORDER BY. Например, если модель Blog определила ordering по name:

Entry.objects.order_by('blog').distinct('blog')

…это не сработает, так как запрос будет отсортирован по blog__name, что не соответствует выражению DISTINCT ON. Вам нужно будет явно отсортировать по полю отношения _id (blog_id в этом случае) или по связанному полю (blog__pk), чтобы убедиться, что оба выражения соответствуют.

values()

values(*fields, **expressions)

Возвращает набор запросов QuerySet, который возвращает словари, а не экземпляры моделей, при использовании в качестве итерируемого объекта.

Каждый из этих словарей представляет объект, с ключами, соответствующими именам атрибутов объектов модели.

Этот пример сравнивает словари values() со стандартными объектами модели:

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

Метод values() принимает необязательные позиционные аргументы, *fields, которые задают имена полей, к которым должен быть ограничен SELECT. Если вы указываете поля, каждый словарь будет содержать только ключи/значения полей, которые вы указали. Если вы не указываете поля, каждый словарь будет содержать ключ и значение для каждого поля в таблице базы данных.

Пример:

>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

Метод values() также принимает необязательные именованные аргументы, **expressions, которые передаются методу annotate():

>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>

Вы можете использовать встроенные и пользовательские правила в сортировке. Например:

>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values('name__lower')
<QuerySet [{'name__lower': 'beatles blog'}]>

Агрегат внутри фрагмента values() применяется перед другими аргументами в том же фрагменте values(). Если вам нужно сгруппировать по другому значению, добавьте его в более ранний фрагмент values() вместо этого. Например:

>>> from django.db.models import Count
>>> Blog.objects.values('entry__authors', entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values('entry__authors').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>

Несколько тонкостей, которые стоит упомянуть:

  • Если у вас есть поле, называемое foo, которое является ForeignKey, то вызов по умолчанию values() вернёт ключ словаря, называемый foo_id, так как это имя скрытого атрибута модели, хранящего фактическое значение (атрибут foo относится к связанной модели). При вызове values() и передаче имён полей, вы можете передать foo или foo_id, и получите то же самое (ключ словаря будет соответствовать имени поля, которое вы передали).

    Например:

    >>> Entry.objects.values()
    <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
    
    >>> Entry.objects.values('blog')
    <QuerySet [{'blog': 1}, ...]>
    
    >>> Entry.objects.values('blog_id')
    <QuerySet [{'blog_id': 1}, ...]>
    
  • При использовании values() вместе с distinct(), имейте в виду, что сортировка может повлиять на результаты. Подробнее см. примечание в distinct().
  • Если вы используете клаузу values() после вызова extra(), любые поля, определённые аргументом select в вызове extra(), должны быть явно включены в вызов values(). Любой вызов extra(), сделанный после вызова values() , проигнорирует дополнительные выбранные поля.
  • Вызов only() и defer() после values() не имеет смысла, поэтому это вызовет TypeError.
  • Для комбинирования преобразований и агрегаций необходимо использовать два вызова annotate(), явно или в качестве ключевых аргументов для values(). Как и выше, если преобразование зарегистрировано для соответствующего типа поля, первый вызов annotate() можно опустить, таким образом следующие примеры эквивалентны:

    >>> from django.db.models import CharField, Count
    >>> from django.db.models.functions import Lower
    >>> CharField.register_lookup(Lower)
    >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry'))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    >>> Blog.objects.values(
    ...     entry__authors__name__lower=Lower('entry__authors__name')
    ... ).annotate(entries=Count('entry'))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    >>> Blog.objects.annotate(
    ...     entry__authors__name__lower=Lower('entry__authors__name')
    ... ).values('entry__authors__name__lower').annotate(entries=Count('entry'))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    

Это полезно, когда вы знаете, что вам понадобятся только значения из небольшого количества доступных полей, и вам не понадобится функциональность объекта модели. Эффективнее выбрать только необходимые поля.

Наконец, обратите внимание, что вы можете вызвать filter(), order_by(), и т.д. после вызова values(), что означает, что эти два вызова идентичны:

Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()

Создатели Django предпочитают сначала размещать все методы, влияющие на SQL, а затем (необязательно) методы, влияющие на вывод (например, values()), но это не имеет большого значения. Это ваш шанс продемонстрировать свою индивидуальность.

Вы также можете ссылаться на поля связанных моделей с обратными связями через атрибуты OneToOneField, ForeignKey и ManyToManyField:

>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
     {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>

Предупреждение

Так как атрибуты ManyToManyField и обратные связи могут иметь несколько связанных строк, их включение может кратно увеличить размер набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в ваш запрос values(), в этом случае будут возвращены все возможные комбинации.

Специальные значения для JSONField в SQLite

Из-за того, как реализованы SQL-функции JSON_EXTRACT и JSON_TYPE в SQLite, и отсутствия типа данных BOOLEAN, values() вернёт True, False, и None вместо "true", "false", и "null" строк для преобразований ключей JSONField.

values_list()

values_list(*fields, flat=False, named=False)

Это аналогично values() за исключением того, что вместо словарей, при итерировании оно возвращает кортежи. Каждый кортеж содержит значение из соответствующего поля или выражения, переданного в вызов values_list() — первый элемент — первое поле и так далее. Например:

>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>

Если вы передаёте только одно поле, вы также можете передать параметр flat. Если True, это означает, что возвращаемые результаты — это отдельные значения, а не кортежи из одного элемента. Пример лучше продемонстрирует разницу:

>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>

>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>

Передача flat при наличии более одного поля — ошибка.

Вы можете передать named=True для получения результатов в виде namedtuple():

>>> Entry.objects.values_list('id', 'headline', named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>

Использование именованного кортежа может сделать использование результатов более читаемым, ценой небольшого снижения производительности из-за преобразования результатов в именованный кортеж.

Если вы не передаёте никаких значений в values_list(), оно вернёт все поля в модели в порядке их объявления.

Распространённая необходимость — получить конкретное значение поля определённого экземпляра модели. Для этого используйте values_list() и get():

>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'

values() и values_list() — оптимизации для конкретного случая: извлечение подмножества данных без накладных расходов на создание экземпляра модели. Эта метафора перестаёт работать при работе с множественными связями и другими многозначными связями (например, с одной-ко-многим связью обратного внешнего ключа), так как предположение «одна строка, один объект» не выполняется.

Например, обратите внимание на поведение при запросе через ManyToManyField:

>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
 ('George Orwell', 'Why Socialists Do Not Believe in Fun'),
 ('George Orwell', 'In Defence of English Cooking'),
 ('Don Quixote', None)]>

Авторы с несколькими записями отображаются несколько раз, а авторы без записей имеют None для заголовка записи.

Аналогично, при запросе обратного внешнего ключа, для записей без авторов отображается None:

>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>

Специальные значения для JSONField в SQLite

Из-за того, как реализованы SQL-функции JSON_EXTRACT и JSON_TYPE в SQLite, и отсутствия типа данных BOOLEAN, values_list() вернёт True, False, и None вместо "true", "false", и "null" строк для преобразований ключей JSONField.

dates()

dates(field, kind, order='ASC')

Возвращает QuerySet, содержащий список объектов datetime.date, представляющих все доступные даты определённого типа в содержимом QuerySet.

field должно быть именем DateField вашей модели. kind должно быть "year", "month", "week", или "day". Каждый объект datetime.date в результате списка «обрезается» до заданного type.

  • "year" возвращает список всех уникальных значений года для поля.
  • "month" возвращает список всех уникальных значений года/месяца для поля.
  • "week" возвращает список всех уникальных значений года/недели для поля. Все даты будут понедельниками.
  • "day" возвращает список всех уникальных значений года/месяца/дня для поля.

order, которое по умолчанию 'ASC', должно быть 'ASC' или 'DESC' . Это определяет порядок сортировки результатов.

Примеры:

>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'week')
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]

datetimes()

datetimes(field_name, kind, order='ASC', tzinfo=None, is_dst=None)

Возвращает QuerySet содержащий список объектов datetime.datetime, представляющих все доступные даты определённого типа в содержимом QuerySet.

field_name должно быть именем DateTimeField вашей модели.

kind должно быть "year", "month", "week", "day", "hour", "minute", или "second". Каждый объект datetime.datetime в результирующем списке «обрезается» до заданного type.

order, по умолчанию 'ASC', должно быть либо 'ASC' или 'DESC'. Это определяет порядок сортировки результатов.

tzinfo определяет часовой пояс, в который преобразуются значения дат и времени до усечения. Действительно, заданная дата и время имеют разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo. Если это None, Django использует текущий часовой пояс. Он не оказывает влияния, когда USE_TZ равно False.

is_dst указывает, следует ли pytz интерпретировать несуществующие и неоднозначные даты и время в летнее время. По умолчанию (если is_dst=None ), pytz генерирует исключение для таких дат и времени.

Устаревшее начиная с версии 4.0: Параметр is_dst устарел и будет удален в Django 5.0.

Примечание

Эта функция выполняет преобразования часовых поясов непосредственно в базе данных. Вследствие этого ваша база данных должна уметь интерпретировать значение tzinfo.tzname(None). Это приводит к следующим требованиям:

  • SQLite: нет требований. Преобразования выполняются в Python.
  • PostgreSQL: нет требований (см. Часовые пояса).
  • Oracle: нет требований (см. Выбор файла часового пояса).
  • MySQL: загрузите таблицы часовых поясов с помощью mysql_tzinfo_to_sql.

none()

none()

Вызов none() создаст набор запросов, который никогда не возвращает объекты, и при обращении к результатам запрос не будет выполнен. Набор запросов qs.none() является экземпляром EmptyQuerySet.

Примеры:

>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True

all()

all()

Возвращает копию текущего набора запросов QuerySet (или подкласса QuerySet). Это может быть полезно в ситуациях, когда вы хотите передать менеджер модели или набор запросов QuerySet и выполнить дополнительную фильтрацию результатов. После вызова all() для любого из объектов вы обязательно получите набор запросов QuerySet для работы.

Когда набор запросов QuerySet оценивается, он обычно кеширует свои результаты. Если данные в базе данных могли измениться с момента оценки набора запросов QuerySet, вы можете получить обновленные результаты для того же запроса, вызвав all() для ранее оцененного набора запросов QuerySet.

union()

union(*other_qs, all=False)

Использует оператор SQL UNION для объединения результатов двух или более наборов запросов QuerySet.

Например:

>>> qs1.union(qs2, qs3)

Оператор UNION по умолчанию выбирает только уникальные значения. Чтобы разрешить дубликаты, используйте аргумент all=True.

union(), intersection(), и difference() возвращают экземпляры моделей того же типа, что и первый набор запросов QuerySet, даже если аргументы являются наборами запросов QuerySet других моделей. Передача разных моделей работает, если список SELECT одинаков во всех наборах запросов QuerySet (по крайней мере, типы, имена не важны, если типы в одинаковом порядке). В таких случаях необходимо использовать имена столбцов из первого набора запросов QuerySet в методах QuerySet, примененных к результирующему набору запросов QuerySet. Например:

>>> qs1 = Author.objects.values_list('name')
>>> qs2 = Entry.objects.values_list('headline')
>>> qs1.union(qs2).order_by('name')

Кроме того, только LIMIT, OFFSET, COUNT(*), ORDER BY, и указание столбцов (например, срез, count(), exists(), order_by() и values()/values_list()) разрешены для результирующего набора запросов QuerySet. Кроме того, базы данных накладывают ограничения на разрешенные операции в объединенных запросах. Например, большинство баз данных не позволяют LIMIT или OFFSET в объединенных запросах.

intersection()

intersection(*other_qs)

Использует оператор SQL INTERSECT для возвращения общих элементов двух или более наборов запросов QuerySet.

Например:

>>> qs1.intersection(qs2, qs3)

См. union() для некоторых ограничений.

difference()

difference(*other_qs)

Использует оператор SQL EXCEPT для сохранения только элементов, присутствующих в QuerySet, но не в других наборах запросов QuerySet.

Например:

>>> qs1.difference(qs2, qs3)

См. union() для некоторых ограничений.

select_related()

select_related(*fields)

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

Следующие примеры иллюстрируют разницу между обычным поиском и поиском с select_related(). Вот стандартный поиск:

# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog

А вот поиск с select_related:

# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog

Вы можете использовать select_related() с любым набором запросов объектов:

from django.utils import timezone

# Find all the blogs with entries scheduled to be published in the future.
blogs = set()

for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):
    # Without select_related(), this would make a database query for each
    # loop iteration in order to fetch the related blog for each entry.
    blogs.add(e.blog)

Порядок цепочки вызовов filter() и select_related() не важен. Эти наборы запросов эквивалентны:

Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())

Вы можете следовать внешним ключам аналогичным способом, как их запрашивать. Если у вас есть следующие модели:

from django.db import models

class City(models.Model):
    # ...
    pass

class Person(models.Model):
    # ...
    hometown = models.ForeignKey(
        City,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

class Book(models.Model):
    # ...
    author = models.ForeignKey(Person, on_delete=models.CASCADE)

… то вызов Book.objects.select_related('author__hometown').get(id=4) кеширует связанные Person и связанные City:

# Hits the database with joins to the author and hometown tables.
b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.

# Without select_related()...
b = Book.objects.get(id=4)  # Hits the database.
p = b.author         # Hits the database.
c = p.hometown       # Hits the database.

Вы можете ссылаться на любую связь ForeignKey или OneToOneField в списке полей, переданных в select_related().

Вы также можете ссылаться на обратное направление связи OneToOneField в списке полей, переданных в select_related — то есть, вы можете пройти по обратной связи OneToOneField обратно к объекту, в котором определено поле. Вместо указания имени поля используйте related_name для поля связанного объекта.

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

Если вам нужно очистить список связанных полей, добавленных предыдущими вызовами select_related для набора запросов QuerySet, вы можете передать None в качестве параметра:

>>> without_relations = queryset.select_related(None)

Цепочка вызовов select_related работает аналогично другим методам — то есть select_related('foo', 'bar') эквивалентно select_related('foo').select_related('bar').

prefetch_related()

prefetch_related(*lookups)

Возвращает набор запросов QuerySet, который автоматически извлечет в одной группе связанные объекты для каждого указанного поиска.

Это имеет аналогичную цель с select_related, так как оба предназначены для предотвращения избыточного количества запросов к базе данных при доступе к связанным объектам, но стратегии различаются.

select_related работает, создавая объединение SQL и включая поля связанного объекта в оператор SELECT. По этой причине select_related получает связанные объекты в одном запросе к базе данных. Однако, чтобы избежать гораздо большего набора результатов, который бы получился при объединении через связь «многие», select_related ограничен связями с одним значением — внешним ключом и один-к-одному.

prefetch_related, с другой стороны, выполняет отдельный поиск для каждой связи и выполняет «соединение» в Python. Это позволяет предварительно загружать объекты «многие ко многим» и «многие к одному», что невозможно сделать с помощью select_related, помимо связей по внешнему ключу и «один к одному», которые поддерживаются select_related. Он также поддерживает предварительную загрузку GenericRelation и GenericForeignKey, однако, он должен быть ограничен однородным набором результатов. Например, предварительная загрузка объектов, на которые ссылается GenericForeignKey, поддерживается только в том случае, если запрос ограничен одним ContentType.

Например, предположим, что у вас есть эти модели:

from django.db import models

class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

    def __str__(self):
        return "%s (%s)" % (
            self.name,
            ", ".join(topping.name for topping in self.toppings.all()),
        )

и запустите:

>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...

Проблема в том, что каждый раз, когда Pizza.__str__() запрашивает self.toppings.all(), он должен обратиться к базе данных, поэтому Pizza.objects.all() будет выполнять запрос к таблице Toppings для каждого элемента в пицце QuerySet.

Мы можем сократить до двух запросов, используя prefetch_related:

>>> Pizza.objects.prefetch_related('toppings')

Это подразумевает self.toppings.all() для каждого Pizza; теперь каждый раз, когда self.toppings.all() вызывается, вместо того, чтобы обращаться к базе данных за элементами, он найдет их в предварительно загруженном QuerySet кэше, который был заполнен в одном запросе.

То есть, все соответствующие дополнения будут извлечены в одном запросе и использованы для создания QuerySets с предварительно заполненным кэшем соответствующих результатов; эти QuerySets затем используются в вызовах self.toppings.all().

Дополнительные запросы в prefetch_related() выполняются после того, как началась оценка QuerySet и был выполнен основной запрос.

Если у вас есть итерируемый список экземпляров модели, вы можете предварительно загрузить связанные атрибуты этих экземпляров, используя функцию prefetch_related_objects().

Обратите внимание, что кэш результатов основного QuerySet и всех указанных связанных объектов затем будут полностью загружены в память. Это изменяет типичное поведение QuerySets, которые обычно пытаются избежать загрузки всех объектов в память до их необходимости, даже после выполнения запроса в базе данных.

Примечание

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

>>> pizzas = Pizza.objects.prefetch_related('toppings')
>>> [list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]

…то тот факт, что pizza.toppings.all() был предварительно загружен, не поможет вам. prefetch_related('toppings') подразумевает pizza.toppings.all(), но pizza.toppings.filter() — это новый и другой запрос. Кэшированный результат предварительной загрузки здесь не поможет; на самом деле это снижает производительность, поскольку вы выполнили запрос к базе данных, который не использовали. Поэтому используйте эту функцию с осторожностью!

Также, если вы вызываете методы изменения базы данных add(), remove(), clear() или set(), на related managers, любой кэш предварительной загрузки для связи будет очищен.

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

class Restaurant(models.Model):
    pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
    best_pizza = models.ForeignKey(Pizza, related_name='championed_by', on_delete=models.CASCADE)

Следующие варианты допустимы:

>>> Restaurant.objects.prefetch_related('pizzas__toppings')

Это предварительно загрузит все пиццы, принадлежащие ресторанам, и все дополнения, принадлежащие этим пиццам. В результате будет выполнено всего 3 запроса к базе данных — один для ресторанов, один для пицц и один для дополнений.

>>> Restaurant.objects.prefetch_related('best_pizza__toppings')

Это позволит загрузить лучшую пиццу и все дополнения к лучшей пицце для каждого ресторана. Это будет выполнено за 3 запроса к базе данных — один для ресторанов, один для «лучших пицц» и один для дополнений.

Связь best_pizza также может быть загружена с использованием select_related для уменьшения количества запросов до 2:

>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')

Поскольку предварительная загрузка выполняется после основного запроса (который включает объединения, необходимые для select_related), он может определить, что объекты best_pizza уже были загружены, и пропустит их повторную загрузку.

Цепочки вызовов prefetch_related будут накапливать запросы, которые предварительно загружаются. Чтобы очистить любое поведение prefetch_related , передайте None в качестве параметра:

>>> non_prefetched = qs.prefetch_related(None)

Одна из особенностей при использовании prefetch_related заключается в том, что объекты, созданные запросом, могут быть общими для различных объектов, с которыми они связаны, т. е. один экземпляр модели Python может появиться более чем в одной точке дерева возвращаемых объектов. Это обычно происходит при отношениях внешнего ключа. Обычно это поведение не представляет проблемы и, фактически, экономит память и время ЦП.

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

prefetch_related в большинстве случаев будет реализован с помощью SQL-запроса, использующего оператор «В». Это означает, что для большого QuerySet может быть сгенерирована большая фраза «В», которая в зависимости от базы данных может иметь собственные проблемы с производительностью при обработке или выполнении SQL-запроса. Всегда проводите профилирование для вашего конкретного случая!

Изменено в Django 4.1:

Если вы используете iterator() для выполнения запроса, вызовы prefetch_related() будут наблюдаться только в том случае, если будет предоставлено значение для chunk_size.

Вы можете использовать объект Prefetch для дальнейшего управления операцией предварительной загрузки.

В своем самом простом виде Prefetch эквивалентен традиционным поискам на основе строк:

>>> from django.db.models import Prefetch
>>> Restaurant.objects.prefetch_related(Prefetch('pizzas__toppings'))

Вы можете предоставить пользовательский набор запросов с необязательным аргументом queryset. Это может быть использовано для изменения стандартного порядка сортировки набора запросов:

>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas__toppings', queryset=Toppings.objects.order_by('name')))

Или для вызова select_related() применительно к уменьшению количества запросов еще больше:

>>> Pizza.objects.prefetch_related(
...     Prefetch('restaurants', queryset=Restaurant.objects.select_related('best_pizza')))

Вы также можете назначить результат предварительной загрузки пользовательскому атрибуту с необязательным аргументом to_attr. Результат будет сохранен непосредственно в списке.

Это позволяет предварительно загружать одну и ту же связь несколько раз с разным QuerySet; например:

>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', to_attr='menu'),
...     Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'))

Поисковые запросы, созданные с помощью настраиваемых to_attr , все равно могут быть пройдены обычным способом другими запросами:

>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'),
...     'vegetarian_menu__toppings')

Использование to_attr рекомендуется при фильтрации результатов предварительной загрузки, так как это менее неоднозначно, чем хранение отфильтрованного результата в кэше связанного менеджера:

>>> queryset = Pizza.objects.filter(vegetarian=True)
>>>
>>> # Recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', queryset=queryset, to_attr='vegetarian_pizzas'))
>>> vegetarian_pizzas = restaurants[0].vegetarian_pizzas
>>>
>>> # Not recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', queryset=queryset))
>>> vegetarian_pizzas = restaurants[0].pizzas.all()

Настраиваемая предварительная загрузка также работает со связанными отношениями, такими как прямое ForeignKey или OneToOneField. Обычно для этих отношений вы захотите использовать select_related(), но есть ряд случаев, когда предварительная загрузка с настраиваемым QuerySet полезна:

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

    >>> queryset = Pizza.objects.only('name')
    >>>
    >>> restaurants = Restaurant.objects.prefetch_related(
    ...     Prefetch('best_pizza', queryset=queryset))
    

При использовании нескольких баз данных Prefetch будет учитывать ваш выбор базы данных. Если внутренний запрос не указывает базу данных, он будет использовать базу данных, выбранную внешним запросом. Все следующие варианты допустимы:

>>> # Both inner and outer queries will use the 'replica' database
>>> Restaurant.objects.prefetch_related('pizzas__toppings').using('replica')
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas__toppings'),
... ).using('replica')
>>>
>>> # Inner will use the 'replica' database; outer will use 'default' database
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas__toppings', queryset=Toppings.objects.using('replica')),
... )
>>>
>>> # Inner will use 'replica' database; outer will use 'cold-storage' database
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas__toppings', queryset=Toppings.objects.using('replica')),
... ).using('cold-storage')

Примечание

Порядок поисковых запросов имеет значение.

Рассмотрим следующие примеры:

>>> prefetch_related('pizzas__toppings', 'pizzas')

Это работает даже без порядка, потому что 'pizzas__toppings' уже содержит всю необходимую информацию, поэтому второй аргумент 'pizzas' на самом деле избыточен.

>>> prefetch_related('pizzas__toppings', Prefetch('pizzas', queryset=Pizza.objects.all()))

Это вызовет ValueError из-за попытки переопределить набор запросов для ранее виденного запроса. Обратите внимание, что неявный набор запросов был создан для прохода по 'pizzas' в качестве части запроса 'pizzas__toppings'.

>>> prefetch_related('pizza_list__toppings', Prefetch('pizzas', to_attr='pizza_list'))

Это приведет к AttributeError , потому что 'pizza_list' еще не существует, когда 'pizza_list__toppings' обрабатывается.

Это соображение не ограничивается использованием Prefetch объектов. Некоторые расширенные методы могут потребовать выполнения запросов в определенном порядке, чтобы избежать создания дополнительных запросов; поэтому рекомендуется всегда тщательно упорядочивать аргументы prefetch_related.

extra()

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

Иногда синтаксис запросов Django сам по себе не может легко выразить сложное условие WHERE . Для этих крайних случаев Django предоставляет модификатор extra() QuerySet — крючок для вставки специфических условий в SQL, генерируемый QuerySet.

Используйте этот метод в крайнем случае

Это старый API, который мы планируем в какой-то момент устареть. Используйте его только в том случае, если вы не можете выразить свой запрос с помощью других методов queryset. Если вам необходимо его использовать, пожалуйста, отправьте запрос с помощью ключа QuerySet.extra со своим случаем использования (сначала проверьте список существующих запросов), чтобы мы могли улучшить API QuerySet, чтобы разрешить удаление extra(). Мы больше не будем улучшать или исправлять ошибки для этого метода.

Например, это использование extra():

>>> qs.extra(
...     select={'val': "select col from sometable where othercol = %s"},
...     select_params=(someparam,),
... )

эквивалентно:

>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

Основное преимущество использования RawSQL заключается в том, что вы можете установить output_field при необходимости. Основной недостаток заключается в том, что если вы ссылаетесь на какое-либо алиас таблицы queryset в сыром SQL, то Django может изменить этот алиас (например, когда queryset используется в качестве подзапроса в другом запросе).

Предупреждение

Вы должны быть очень осторожны при использовании extra(). Каждый раз, когда вы его используете, вы должны экранировать любые параметры, которые пользователь может контролировать, используя params, чтобы защититься от атак SQL-инъекции.

Вы также не должны заключать в кавычки плейсхолдеры в строке SQL. Этот пример уязвим для атаки SQL-инъекции из-за кавычек вокруг %s:

SELECT col FROM sometable WHERE othercol = '%s'  # unsafe!

Вы можете узнать больше о том, как работает защита от атак SQL-инъекции Django в защите от SQL-инъекции.

По определению, эти дополнительные запросы могут быть не переносимы на разные базы данных (потому что вы явно пишете SQL-код) и нарушают принцип DRY, поэтому следует избегать их, если это возможно.

Укажите один или несколько из params, select, where или tables. Ни один из аргументов не является обязательным, но вы должны использовать хотя бы один из них.

  • select

    Аргумент select позволяет поместить дополнительные поля в SELECT условие. Он должен быть словарем, сопоставляющим имена атрибутов с SQL-фрагментами для вычисления этого атрибута.

    Пример:

    Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    

    В результате у каждого объекта Entry будет дополнительный атрибут is_recent, булевое значение, представляющее, больше ли запись pub_date 1 января 2006 года.

    Django вставляет указанный SQL-фрагмент напрямую в SELECT оператор, поэтому результирующий SQL в приведенном выше примере будет чем-то вроде:

    SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
    FROM blog_entry;
    

    Следующий пример более сложный; он выполняет подзапрос, чтобы дать каждому результативному объекту Blog атрибут entry_count, целочисленный счет связанных объектов Entry:

    Blog.objects.extra(
        select={
            'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
        },
    )
    

    В этом конкретном случае мы используем тот факт, что запрос уже будет содержать таблицу blog_blog в своём FROM условии.

    Результирующий SQL в приведенном выше примере будет:

    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
    FROM blog_blog;
    

    Обратите внимание, что скобки, необходимые большинству баз данных для подзапросов, не требуются в select-условиях Django. Также обратите внимание, что некоторые серверы баз данных, такие как некоторые версии MySQL, не поддерживают подзапросы.

    В некоторых редких случаях вам может потребоваться передать параметры в SQL-фрагменты в extra(select=...). Для этого используйте параметр select_params.

    Это будет работать, например:

    Blog.objects.extra(
        select={'a': '%s', 'b': '%s'},
        select_params=('one', 'two'),
    )
    

    Если вам нужно использовать литерал %s в строке select, используйте последовательность %%s.

  • where / tables

    Вы можете определить явные SQL WHERE условия — возможно, для выполнения неявных объединений — с помощью where . Вы можете вручную добавлять таблицы в FROM условие SQL с помощью tables.

    where и tables оба принимают список строк. Все параметры where «И» с другими условиями поиска.

    Пример:

    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    

    …приблизительно переводится в следующий SQL:

    SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
    

    Будьте осторожны при использовании параметра tables если вы указываете таблицы, которые уже используются в запросе. Когда вы добавляете дополнительные таблицы через параметр tables, Django предполагает, что вы хотите, чтобы эта таблица включалась еще раз, если она уже включена. Это создает проблему, поскольку имя таблицы затем получит алиас. Если таблица появляется несколько раз в операторе SQL, второй и последующие вхождения должны использовать алиасы, чтобы база данных могла их различать. Если вы ссылаетесь на дополнительную таблицу, которую вы добавили в параметре where extra, это вызовет ошибки.

    Обычно вы будете добавлять только дополнительные таблицы, которые уже не появляются в запросе. Однако, если указанный выше случай произойдет, есть несколько решений. Сначала посмотрите, можете ли вы обойтись без включения дополнительной таблицы и использовать ту, которая уже есть в запросе. Если это невозможно, поместите свой вызов extra() в начало построения queryset, чтобы ваша таблица была первым использованием этой таблицы. Наконец, если ничего не поможет, посмотрите на сгенерированный запрос и перепишите добавление where extra, чтобы использовать алиас, присвоенный вашей дополнительной таблице. Алиас будет одинаковым каждый раз, когда вы строите queryset одинаковым образом, поэтому вы можете полагаться на имя алиаса, чтобы оно не изменилось.

  • order_by

    Если вам нужно отсортировать результирующий queryset, используя некоторые новые поля или таблицы, которые вы включили с помощью extra(), используйте параметр order_by для extra() и передайте последовательность строк. Эти строки должны быть полями модели (как в обычном методе order_by() querysets), или в формате table_name.column_name или алиасом столбца, который вы указали в параметре select для extra().

    Например:

    q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    q = q.extra(order_by = ['-is_recent'])
    

    Это отсортирует все элементы, для которых is_recent является истинным, в начале набора результатов (True сортируется перед False в порядке убывания).

    Это показывает, что вы можете сделать несколько вызовов extra() и он будет вести себя так, как вы ожидаете (добавляя новые ограничения каждый раз).

  • params

    Указанный выше параметр where может использовать стандартные плейсхолдеры строк Python для баз данных — '%s' для обозначения параметров, которые база данных должна автоматически заключать в кавычки. Аргумент params — список дополнительных параметров для подстановки.

    Пример:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

    Всегда используйте params вместо встраивания значений непосредственно в where, потому что params гарантирует, что значения будут заключены в кавычки в соответствии с вашей конкретной базой данных. Например, кавычки будут правильно экранированы.

    Плохо:

    Entry.objects.extra(where=["headline='Lennon'"])
    

    Хорошо:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

Предупреждение

Если вы выполняете запросы к MySQL, обратите внимание, что бесшумная приведение типов в MySQL может привести к неожиданным результатам при смешивании типов. Если вы запрашиваете столбец строкового типа, но с целочисленным значением, MySQL приведёт типы всех значений в таблице к целочисленному перед выполнением сравнения. Например, если ваша таблица содержит значения 'abc', 'def' и вы запрашиваете WHERE mycolumn=0, обе строки будут соответствовать. Чтобы предотвратить это, выполните правильное приведение типов перед использованием значения в запросе.

defer()

defer(*fields)

В некоторых сложных ситуациях моделирования данных ваши модели могут содержать много полей, некоторые из которых могут содержать много данных (например, текстовые поля) или требуют дорогостоящей обработки для преобразования в объекты Python. Если вы используете результаты queryset в ситуации, где вы не знаете, нужны ли вам эти конкретные поля, когда вы изначально получаете данные, вы можете указать Django не извлекать их из базы данных.

Это делается путем передачи имен полей, которые не нужно загружать, в defer():

Entry.objects.defer("headline", "body")

Queryset с отложенными полями все равно вернет экземпляры модели. Каждое отложенное поле будет извлечено из базы данных, если вы обращаетесь к этому полю (по одному за раз, а не ко всем отложенным полям сразу).

Примечание

Отложенные поля не будут загружаться лениво из асинхронного кода. Вместо этого вы получите исключение SynchronousOnlyOperation . Если вы пишете асинхронный код, вы не должны пытаться получить доступ к любым полям, которые вы defer().

Вы можете сделать несколько вызовов defer() . Каждый вызов добавляет новые поля в набор отложенных:

# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")

Порядок добавления полей в отложенный набор не имеет значения. Вызов defer() с именем поля, которое уже отложено, не повлияет (поле все равно будет отложено).

Вы можете отложить загрузку полей в связанных моделях (если связанные модели загружаются с помощью select_related()), используя стандартную двойную подчёркнутую нотацию для разделения связанных полей:

Blog.objects.select_related().defer("entry__headline", "entry__body")

Если вы хотите очистить набор отложенных полей, передайте None в качестве параметра к defer():

# Load all fields immediately.
my_queryset.defer(None)

Некоторые поля в модели не будут отложены, даже если вы их запросите. Вы никогда не можете отложить загрузку первичного ключа. Если вы используете select_related() для получения связанных моделей, вы не должны откладывать загрузку поля, которое соединяет первичную модель с связанной, так как это приведёт к ошибке.

Примечание

Метод defer() (и его аналог, only(), ниже) предназначен только для продвинутых случаев. Они обеспечивают оптимизацию, когда вы тщательно проанализировали запросы и точно знаете, какая информация вам нужна, и измерили, что различие между возвратом необходимых полей и полного набора полей модели будет значительным.

Даже если вы считаете, что находитесь в ситуации продвинутого использования, используйте ``defer()`` только тогда, когда во время загрузки набора запросов невозможно определить, понадобятся ли дополнительные поля или нет. Если вы часто загружаете и используете определенный подмножество данных, лучшим выбором будет нормализация ваших моделей и размещение не загружаемых данных в отдельную модель (и таблицу базы данных). Если по какой-то причине столбцы должны остаться в одной таблице, создайте модель с Meta.managed = False (см. managed attribute документацию), содержащую только поля, которые вам обычно нужно загружать и использовать, где вы в противном случае могли бы вызвать defer(). Это делает ваш код более понятным для читателя, немного быстрее и потребляет немного меньше памяти в процессе Python.

Например, обе эти модели используют одну и ту же базу данных:

class CommonlyUsedModel(models.Model):
    f1 = models.CharField(max_length=10)

    class Meta:
        managed = False
        db_table = 'app_largetable'

class ManagedModel(models.Model):
    f1 = models.CharField(max_length=10)
    f2 = models.CharField(max_length=10)

    class Meta:
        db_table = 'app_largetable'

# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer('f2')

Если во вспомогательной модели необходимо дублировать много полей, лучше всего создать абстрактную модель со общими полями, а затем сделать, чтобы не управляемые и управляемые модели наследовали от абстрактной модели.

Примечание

При вызове save() для экземпляров с отложенными полями, будут сохранены только загруженные поля. Подробнее см. save().

only()

only(*fields)

Метод only() более или менее является противоположностью defer(). Вы вызываете его с полями, которые не должны быть отложенными при получении модели. Если у вас есть модель, где почти все поля нужно отложить, использование only() для указания дополнительного набора полей может привести к более простому коду.

Предположим, у вас есть модель с полями name, age и biography. Два следующих набора запросов эквивалентны по отложенным полям:

Person.objects.defer("age", "biography")
Person.objects.only("name")

Каждый раз, когда вы вызываете only() он заменяет набор полей для немедленной загрузки. Имя метода подсказывает: только эти поля загружаются немедленно; остальные откладываются. Таким образом, последовательные вызовы only() приводят к тому, что только конечные поля учитываются:

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

Поскольку defer() работает по частям (добавляя поля в список отложенных), вы можете объединить вызовы only() и defer() и всё будет работать логично:

# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")

# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")

Все предостережения в примечании для defer() документации также относятся к only(). Используйте его осторожно и только после исчерпания других вариантов.

Использование only() и пропуск поля, запрошенного с помощью select_related() также является ошибкой.

Как и с defer(), вы не можете получить доступ к не загруженным полям из асинхронного кода и ожидать их загрузки. Вместо этого вы получите исключение SynchronousOnlyOperation. Убедитесь, что все поля, к которым вы можете получить доступ, находятся в вашем вызове only().

Примечание

При вызове save() для экземпляров с отложенными полями, будут сохранены только загруженные поля. Подробнее см. save().

using()

using(alias)

Этот метод используется для управления базой данных, к которой будет применяться QuerySet , если вы используете более одной базы данных. Единственный аргумент этого метода — псевдоним базы данных, как определено в DATABASES.

Например:

# queries the database with the 'default' alias.
>>> Entry.objects.all()

# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')

select_for_update()

select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)

Возвращает набор запросов, который будет блокировать строки до конца транзакции, генерируя SELECT ... FOR UPDATE оператор SQL на поддерживаемых базах данных.

Например:

from django.db import transaction

entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
    for entry in entries:
        ...

При оценке набора запросов (for entry in entries в данном случае), все соответствующие записи будут заблокированы до конца блока транзакции, что означает, что другие транзакции будут предотвращены от изменения или получения блокировок на них.

Обычно, если другая транзакция уже получила блокировку одной из выбранных строк, запрос будет блокироваться до тех пор, пока блокировка не будет освобождена. Если это не то поведение, которое вы хотите, вызовите select_for_update(nowait=True). Это сделает вызов неблокирующим. Если другая транзакция уже получила конфликтую блокировку, при оценке набора запросов будет поднято исключение DatabaseError. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True) вместо. nowait и skip_locked взаимно исключают друг друга, и попытка вызвать select_for_update() с обоими параметрами включенными приведет к ValueError.

По умолчанию, select_for_update() блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанных в select_related() блокируются в дополнение к строкам модели набора запросов. Если этого не требуется, укажите связанные объекты, которые нужно заблокировать в select_for_update(of=(...)) используя ту же синтаксис полей, что и в select_related(). Используйте значение 'self' для ссылки на модель набора запросов.

Блокировка родительских моделей в select_for_update(of=(...))

Если вы хотите заблокировать родительские модели при использовании наследования по нескольким таблицам, вы должны указать поля родительской ссылки (по умолчанию <parent_model_name>_ptr) в аргументе of. Например:

Restaurant.objects.select_for_update(of=('self', 'place_ptr'))

Использование select_for_update(of=(...)) со специфицированными полями

Если вы хотите заблокировать модели и указать выбранные поля, например, используя values(), вы должны выбрать хотя бы одно поле из каждой модели в аргументе of . Модели без выбранных полей не будут заблокированы.

Только в PostgreSQL вы можете передать no_key=True для получения более слабой блокировки, которая всё ещё позволяет создавать строки, которые просто ссылаются на заблокированные строки (например, через внешний ключ), пока блокировка активна. В документации PostgreSQL содержатся дополнительные сведения о режимах блокировок на уровне строк.

Вы не можете использовать select_for_update() на нулевых отношениях:

>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join

Чтобы избежать этого ограничения, вы можете исключить нулевые объекты, если вам не важны эти объекты:

>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>

Бэкенды баз данных postgresql, oracle, и mysql поддерживают select_for_update(). Однако, MariaDB поддерживает только аргумент nowait, MariaDB 10.6+ также поддерживает аргумент skip_locked, а MySQL 8.0.1+ поддерживает аргументы nowait, skip_locked, и of . Аргумент no_key поддерживается только в PostgreSQL.

Передача nowait=True, skip_locked=True, no_key=True, или of в select_for_update() с помощью бэкендов баз данных, которые не поддерживают эти опции, такие как MySQL, вызывает NotSupportedError. Это предотвращает непредвиденное блокирование кода.

Оценивание набора запросов с select_for_update() в режиме autocommit на бэкендах, которые поддерживают SELECT ... FOR UPDATE - это ошибка TransactionManagementError, поскольку строки в этом случае не блокируются. Если это разрешено, это могло бы способствовать порче данных и легко могло быть вызвано кодом, который ожидает выполнения вне транзакции.

Использование select_for_update() на бэкендах, которые не поддерживают SELECT ... FOR UPDATE (например, SQLite), не оказывает никакого влияния. SELECT ... FOR UPDATE не будет добавлен в запрос, и ошибка не возникает, если select_for_update() используется в режиме autocommit.

Предупреждение

Хотя select_for_update() обычно завершается ошибкой в режиме автосохранения, так как TestCase автоматически оборачивает каждый тест в транзакцию, вызов select_for_update() в TestCase даже вне блока atomic() будет (возможно, неожиданно) выполнен без подъема ошибки TransactionManagementError. Для правильного тестирования select_for_update() следует использовать TransactionTestCase.

Некоторые выражения могут быть не поддерживаемы

PostgreSQL не поддерживает select_for_update() с выражениями Window.

Изменено в Django 4.0:

Аргумент skip_locked был разрешён для MariaDB 10.6+.

raw()

raw(raw_query, params=(), translations=None, using=None)

Принимает SQL-запрос, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet. Этот экземпляр RawQuerySet можно перебирать, как и обычный QuerySet, для получения экземпляров объектов.

Для получения дополнительной информации см. Выполнение SQL-запросов.

Предупреждение

raw() всегда запускает новый запрос и не учитывает предыдущую фильтрацию. Поэтому его следует вызывать обычно из Manager или из нового экземпляра QuerySet.

Операторы, возвращающие новые QuerySet

Объединённые запросы должны использовать одну и ту же модель.

И (&)

Объединяет два QuerySet с помощью оператора SQL AND.

Следующие выражения эквивалентны:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))

Эквивалент в SQL:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))

ИЛИ (|)

Объединяет два QuerySet с помощью оператора SQL OR.

Следующие выражения эквивалентны:

Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))

Эквивалент в SQL:

SELECT ... WHERE x=1 OR y=2

| не является коммутативной операцией, так как могут быть сгенерированы различные (хотя и эквивалентные) запросы.

ИСКЛЮЧАЮЩЕЕ ИЛИ (^)

Новое в Django 4.1.

Объединяет два QuerySet с помощью оператора SQL XOR.

Следующие выражения эквивалентны:

Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) ^ Q(y=2))

Эквивалент в SQL:

SELECT ... WHERE x=1 XOR y=2

Примечание

XOR изначально поддерживается в MariaDB и MySQL. В других базах данных x ^ y ^ ... ^ z преобразуется в эквивалент:

(x OR y OR ... OR z) AND
1=(
    (CASE WHEN x THEN 1 ELSE 0 END) +
    (CASE WHEN y THEN 1 ELSE 0 END) +
    ...
    (CASE WHEN z THEN 1 ELSE 0 END) +
)

Методы, не возвращающие QuerySet

Следующие методы QuerySet вычисляют QuerySet и возвращают что-то кроме QuerySet.

Эти методы не используют кэширование (см. Кэширование и QuerySet). Вместо этого они каждый раз обращаются к базе данных.

Поскольку эти методы вычисляют QuerySet, они являются блокирующими вызовами, и поэтому их основные (синхронные) версии нельзя вызывать из асинхронного кода. По этой причине каждый из них имеет соответствующую асинхронную версию с префиксом a - например, вместо get(…) можно использовать await aget(…).

Обычно в поведении нет различий, за исключением асинхронного характера, но любые различия указаны ниже рядом с каждым методом.

Изменено в Django 4.1:

Были добавлены асинхронные версии каждого метода с префиксом a.

get()

get(*args, **kwargs)
aget(*args, **kwargs)

Асинхронная версия: aget()

Возвращает объект, соответствующий заданным параметрам поиска, которые должны быть в формате, описанном в Поиск по полям. Следует использовать уникальные поиски, такие как первичный ключ или поля в уникальном ограничении. Например:

Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))

Если ожидается, что запрос вернёт одну строку, можно использовать get() без аргументов для возврата объекта этой строки:

Entry.objects.filter(pk=1).get()

Если get() не найдёт объект, возникает исключение Model.DoesNotExist:

Entry.objects.get(id=-999) # raises Entry.DoesNotExist

Если get() найдёт более одного объекта, возникает исключение Model.MultipleObjectsReturned:

Entry.objects.get(name='A Duplicated Name') # raises Entry.MultipleObjectsReturned

Оба этих класса исключений являются атрибутами класса модели и специфичны для этой модели. Если вы хотите обрабатывать такие исключения из нескольких вызовов get() для разных моделей, вы можете использовать их общие базовые классы. Например, вы можете использовать django.core.exceptions.ObjectDoesNotExist для обработки исключений DoesNotExist из нескольких моделей:

from django.core.exceptions import ObjectDoesNotExist

try:
    blog = Blog.objects.get(id=1)
    entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
    print("Either the blog or entry doesn't exist.")
Изменено в Django 4.1:

Был добавлен метод aget().

create()

create(**kwargs)
acreate(*args, **kwargs)

Асинхронная версия: acreate()

Удобный метод для создания объекта и его сохранения в одном шаге. Таким образом:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

и:

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)

эквивалентны.

Параметр force_insert документирован в другом месте, но он просто означает, что всегда будет создан новый объект. Обычно вам об этом беспокоиться не нужно. Однако, если ваша модель содержит ручное значение первичного ключа, которое вы задаёте, и если это значение уже существует в базе данных, вызов create() завершится с ошибкой IntegrityError, так как первичные ключи должны быть уникальными. Будьте готовы обработать это исключение, если используете ручные первичные ключи.

Изменено в Django 4.1:

Был добавлен метод acreate().

Получить или создать (get_or_create())

get_or_create(defaults=None, **kwargs)
aget_or_create(defaults=None, **kwargs)

Асинхронная версия: aget_or_create()

Удобный метод для поиска объекта с заданными kwargs (может быть пустым, если ваша модель имеет значения по умолчанию для всех полей), создавая его, если необходимо.

Возвращает кортеж из (object, created), где object — это полученный или созданный объект, а created — булево значение, указывающее, был ли создан новый объект.

Это призвано предотвратить создание дублирующих объектов при одновременных запросах и служит сокращением для шаблонного кода. Например:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

Здесь, при одновременных запросах, могут быть сделаны несколько попыток сохранения Person с одинаковыми параметрами. Чтобы избежать этой гонки, приведенный выше пример можно переписать, используя get_or_create() следующим образом:

obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

Любые ключевые аргументы, передаваемые в get_or_create() — кроме необязательного аргумента, называемого defaults — будут использованы в вызове get(). Если объект найден, get_or_create() возвращает кортеж этого объекта и False.

Предупреждение

Этот метод предполагает атомарность, предполагая, что база данных обеспечивает уникальность ключевых аргументов (см. unique или unique_together). Если поля, используемые в ключевых аргументах, не имеют ограничения уникальности, одновременные вызовы этого метода могут привести к вставке нескольких строк с одинаковыми параметрами.

Вы можете указать более сложные условия для полученного объекта, объединяя get_or_create() с filter() и используя Q objects. Например, для получения Роберта или Боба Марли, если любой из них существует, и создания последнего в противном случае:

from django.db.models import Q

obj, created = Person.objects.filter(
    Q(first_name='Bob') | Q(first_name='Robert'),
).get_or_create(last_name='Marley', defaults={'first_name': 'Bob'})

Если найдено несколько объектов, get_or_create() вызывает MultipleObjectsReturned. Если объект не найден, get_or_create() создаст и сохранит новый объект, вернув кортеж из нового объекта и True. Новый объект будет создан приблизительно по следующему алгоритму:

params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()

На английском это означает начать с любого не-'defaults' ключевого аргумента, который не содержит двойного подчеркивания (что указывает на неточный поиск). Затем добавить содержимое defaults, переопределяя необходимые ключи, и использовать результат в качестве ключевых аргументов для класса модели. Если в defaults есть вызываемые объекты, вычислите их. Как намекалось выше, это упрощённый алгоритм, но он содержит все существенные детали. Внутренняя реализация имеет больше проверок ошибок и обрабатывает дополнительные граничные условия; если вас это интересует, прочитайте код.

Если у вас есть поле с именем defaults и вы хотите использовать его как точный поиск в get_or_create(), используйте 'defaults__exact', как показано ниже:

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

Метод get_or_create() имеет аналогичное поведение при ошибках, как create() при использовании вручную указанных первичных ключей. Если необходимо создать объект, а ключ уже существует в базе данных, будет поднято исключение IntegrityError.

Наконец, несколько слов о применении get_or_create() в представлениях Django. Пожалуйста, убедитесь, что вы используете его только в POST запросах, если у вас нет веской причины не делать этого. GET запросы не должны оказывать никакого влияния на данные. Вместо этого используйте POST всякий раз, когда запрос на страницу имеет побочный эффект на ваши данные. Более подробную информацию см. в Безопасных методах в спецификации HTTP.

Предупреждение

Вы можете использовать get_or_create() через атрибуты ManyToManyField и обратные связи. В этом случае вы ограничите запросы в контексте этой связи. Это может привести к проблемам целостности, если вы не используете его последовательно.

Предположим следующие модели:

class Chapter(models.Model):
    title = models.CharField(max_length=255, unique=True)

class Book(models.Model):
    title = models.CharField(max_length=256)
    chapters = models.ManyToManyField(Chapter)

Вы можете использовать get_or_create() через поле глав книги, но оно извлекает данные только в контексте этой книги:

>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError

Это происходит потому, что система пытается получить или создать «Главу 1» через книгу «Улисс», но не может выполнить ни то, ни другое: связь не может извлечь эту главу, так как она не связана с этой книгой, но и не может её создать, так как поле title должно быть уникальным.

Изменено в Django 4.1:

Метод aget_or_create() был добавлен.

update_or_create()

update_or_create(defaults=None, **kwargs)
aupdate_or_create(defaults=None, **kwargs)

Асинхронная версия: aupdate_or_create()

Удобный метод для обновления объекта с заданными kwargs, создавая новый, если необходимо. defaults — это словарь пар (поле, значение), используемых для обновления объекта. Значения в defaults могут быть вызываемыми объектами.

Возвращает кортеж из (object, created), где object — это созданный или обновлённый объект, а created — булево значение, указывающее, был ли создан новый объект.

Метод update_or_create пытается извлечь объект из базы данных на основе заданного kwargs. Если совпадение найдено, он обновляет поля, переданные в defaults словаре.

Это предназначено как сокращение для громоздкого кода. Например:

defaults = {'first_name': 'Bob'}
try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in defaults.items():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    new_values = {'first_name': 'John', 'last_name': 'Lennon'}
    new_values.update(defaults)
    obj = Person(**new_values)
    obj.save()

Этот шаблон становится слишком громоздким по мере увеличения числа полей в модели. Приведённый выше пример можно переписать с использованием update_or_create() следующим образом:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

Подробное описание того, как решаются имена, переданные в kwargs, см. в get_or_create().

Как описано выше в get_or_create(), этот метод подвержен гонке, которая может привести к одновременной вставке нескольких строк, если уникальность не обеспечена на уровне базы данных.

Как и get_or_create() и create(), если вы используете вручную заданные первичные ключи и необходимо создать объект, но ключ уже существует в базе данных, будет поднято исключение IntegrityError.

Изменено в Django 4.1:

Метод aupdate_or_create() был добавлен.

bulk_create()

bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
abulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)

Асинхронная версия: abulk_create()

Этот метод вставляет предоставленный список объектов в базу данных эффективным способом (как правило, только 1 запрос, независимо от количества объектов) и возвращает созданные объекты в виде списка в том же порядке, что и предоставленный:

>>> objs = Entry.objects.bulk_create([
...     Entry(headline='This is a test'),
...     Entry(headline='This is only a test'),
... ])

Однако это имеет ряд ограничений:

  • Метод модели save() не будет вызываться, и сигналы pre_save и post_save не будут отправлены.
  • Он не работает с дочерними моделями в сценарии наследования с несколькими таблицами.
  • Если первичный ключ модели — это AutoField, атрибут первичного ключа можно получить только на определённых базах данных (в настоящее время PostgreSQL, MariaDB 10.5+, и SQLite 3.35+). На других базах данных он не будет установлен.
  • Он не работает с множественными взаимосвязями.
  • Он преобразует objs в список, который полностью вычисляет objs , если это генератор. Преобразование позволяет инспектировать все объекты, поэтому любые объекты с вручную заданным первичным ключом можно вставить первыми. Если вы хотите вставлять объекты по частям, не оценивая весь генератор сразу, вы можете использовать эту технику, при условии, что у объектов нет вручную заданных первичных ключей:

    from itertools import islice
    
    batch_size = 100
    objs = (Entry(headline='Test %s' % i) for i in range(1000))
    while True:
        batch = list(islice(objs, batch_size))
        if not batch:
            break
        Entry.objects.bulk_create(batch, batch_size)
    

Параметр batch_size управляет количеством объектов, создаваемых в одном запросе. По умолчанию все объекты создаются в одной партии, за исключением SQLite, где по умолчанию используется максимум 999 переменных на запрос.

На базах данных, которые его поддерживают (все, кроме Oracle), установка параметра ignore_conflicts в True сообщает базе данных игнорировать ошибку вставки строк, которые нарушают ограничения, такие как дубликаты уникальных значений.

На базах данных, которые его поддерживают (все, кроме Oracle и SQLite < 3.24), установка параметра update_conflicts в True, сообщает базе данных обновить update_fields, когда вставка строки терпит неудачу из-за конфликтов. В PostgreSQL и SQLite, помимо update_fields, необходимо предоставить список unique_fields , которые могут быть в конфликте.

Включение параметров ignore_conflicts или update_conflicts отключает установку первичного ключа для каждого экземпляра модели (если база данных его обычно поддерживает).

Предупреждение

В MySQL и MariaDB установка параметра ignore_conflicts в True преобразует определённые типы ошибок, отличные от дублирования ключа, в предупреждения. Даже при включённом строгом режиме. Например: некорректные значения или нарушения обязательности полей. Для получения дополнительной информации обратитесь к документации MySQL по теме sql-mode и документации MariaDB по теме ignore.

Изменено в Django 4.0:

Добавлена поддержка извлечения атрибутов первичного ключа в SQLite 3.35+.

Изменено в Django 4.1:

Добавлены параметры update_conflicts, update_fields, и unique_fields для поддержки обновления полей при неудаче вставки строки из-за конфликта.

Метод abulk_create() был добавлен.

bulk_update()

bulk_update(objs, fields, batch_size=None)
abulk_update(objs, fields, batch_size=None)

Асинхронная версия: abulk_update()

Этот метод эффективно обновляет заданные поля в предоставленных экземплярах модели, как правило, с одним запросом, и возвращает количество обновлённых объектов:

>>> objs = [
...    Entry.objects.create(headline='Entry 1'),
...    Entry.objects.create(headline='Entry 2'),
... ]
>>> objs[0].headline = 'This is entry 1'
>>> objs[1].headline = 'This is entry 2'
>>> Entry.objects.bulk_update(objs, ['headline'])
2
Изменено в Django 4.0:

Добавлено возвращаемое значение — количество обновлённых объектов.

QuerySet.update() используется для сохранения изменений, поэтому это более эффективно, чем итерация по списку моделей и вызов save() для каждой из них, но у этого есть несколько ограничений:

  • Вы не можете обновить первичный ключ модели.
  • Метод save() каждой модели не вызывается, и сигналы pre_save и post_save не отправляются.
  • Если вы обновляете большое количество столбцов в большом количестве строк, сгенерированное SQL-запрос может быть очень большим. Избегайте этого, указав подходящий batch_size.
  • Обновление полей, определенных в родительских моделях наследования с несколькими таблицами, приведет к выполнению дополнительного запроса на родительскую модель.
  • Если отдельная группа содержит дубликаты, только первый экземпляр в этой группе приведет к обновлению.
  • Количество обновленных объектов, возвращаемых функцией, может быть меньше, чем количество переданных объектов. Это может быть вызвано передачей дублирующих объектов, которые обновляются в одной группе, или проблемами конкурентного доступа, в результате которых объекты больше не присутствуют в базе данных.

Параметр batch_size управляет количеством объектов, сохраняемых в одном запросе. По умолчанию все объекты обновляются в одной группе, за исключением SQLite и Oracle, которые имеют ограничения на количество переменных, используемых в запросе.

Изменено в Django 4.1:

Добавлен метод abulk_update().

count()

count()
acount()

Асинхронная версия: acount()

Возвращает целое число, представляющее количество объектов в базе данных, соответствующих QuerySet.

Пример:

# Returns the total number of entries in the database.
Entry.objects.count()

# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()

Вызов count() выполняет запрос SELECT COUNT(*) за кулисами, поэтому вы всегда должны использовать count() вместо загрузки всех записей в объекты Python и вызова len() на результате (если только вам не нужно загрузить объекты в память, в этом случае len() будет быстрее).

Обратите внимание, что если вам нужно количество элементов в QuerySet и вы также получаете экземпляры модели из него (например, перебирая его), то, вероятно, эффективнее использовать len(queryset), что не вызовет дополнительного запроса к базе данных, как count().

Если набор запросов уже полностью получен, count() будет использовать его длину, а не выполнять дополнительный запрос к базе данных.

Изменено в Django 4.1:

Добавлен метод acount().

in_bulk()

in_bulk(id_list=None, *, field_name='pk')
ain_bulk(id_list=None, *, field_name='pk')

Асинхронная версия: ain_bulk()

Принимает список значений поля (id_list) и field_name для этих значений и возвращает словарь, сопоставляющий каждое значение с экземпляром объекта с данным значением поля. Исключение django.core.exceptions.ObjectDoesNotExist никогда не будет поднято in_bulk; то есть любое значение id_list не совпадающее с каким-либо экземпляром, будет просто проигнорировано. Если id_list не указано, возвращаются все объекты в наборе запросов. field_name должно быть уникальным полем или отдельным полем (если в distinct() указано только одно поле). field_name по умолчанию равно первичному ключу.

Пример:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct('name').in_bulk(field_name='name')
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}

Если вы передадите in_bulk() пустой список, вы получите пустой словарь.

Изменено в Django 4.1:

Добавлен метод ain_bulk().

iterator()

iterator(chunk_size=None)
aiterator(chunk_size=None)

Асинхронная версия: aiterator()

Вычисляет QuerySet (выполняя запрос) и возвращает итератор (см. PEP 234) по результатам или асинхронный итератор (см. PEP 492), если вы вызываете его асинхронную версию aiterator.

Набор запросов обычно кеширует свои результаты, чтобы повторные вычисления не приводили к дополнительным запросам. В отличие от этого, iterator() будет читать результаты напрямую, не выполняя кеширование на уровне QuerySet (внутренне, итератор по умолчанию вызывает iterator() и кеширует возвращаемое значение). Для набора запросов, возвращающего большое количество объектов, к которым вам нужно получить доступ только один раз, это может улучшить производительность и существенно уменьшить потребление памяти.

Обратите внимание, что использование iterator() на наборе запросов, который уже был вычислен, заставит его перевычисляться, повторив запрос.

iterator() совместим с предыдущими вызовами prefetch_related(), пока chunk_size задано. Более большие значения потребуют меньше запросов для достижения предварительной выборки за счет большего потребления памяти.

Примечание

aiterator() не совместим с предыдущими вызовами prefetch_related().

В некоторых базах данных (например, Oracle, SQLite) может быть ограничено максимальное количество терминов в SQL-запросе IN клаузе. Поэтому следует использовать значения ниже этого предела. (В частности, при предварительной выборке по двум или более отношениям chunk_size должно быть достаточно небольшим, чтобы ожидаемое количество результатов для каждого предварительно выбранного отношения все еще оставалось ниже предела.)

До тех пор, пока набор запросов не предварительно выбирает связанные объекты, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявное значение по умолчанию 2000.

В зависимости от базы данных, результаты запроса будут загружены все сразу или будут поступать из базы данных с использованием серверных курсоров.

Изменено в Django 4.1:

Поддержка предварительной выборки связанных объектов была добавлена в iterator().

Добавлен метод aiterator().

Устарело начиная с версии 4.1: Использование iterator() на наборе запросов, который предварительно выбирает связанные объекты без предоставления chunk_size устарело. В Django 5.0 будет возбуждено исключение.

С серверными курсорами

Oracle и PostgreSQL используют серверные курсоры для потоковой передачи результатов из базы данных без загрузки всего набора результатов в память.

Драйвер базы данных Oracle всегда использует серверные курсоры.

При использовании серверных курсоров параметр chunk_size определяет количество результатов, которые будут кэшироваться на уровне драйвера базы данных. Загрузка больших фрагментов уменьшает количество раундов обмена между драйвером базы данных и базой данных, за счет увеличения потребления памяти.

В PostgreSQL серверные курсоры будут использоваться только тогда, когда настройка DISABLE_SERVER_SIDE_CURSORS имеет значение False. Прочитайте Пулы транзакций и серверные курсоры, если вы используете пул подключений, настроенный в режиме пула транзакций. Когда серверные курсоры отключены, поведение такое же, как у баз данных, которые не поддерживают серверные курсоры.

Без серверных курсоров

MySQL не поддерживает потоковую передачу результатов, поэтому драйвер базы данных Python загружает весь набор результатов в память. Затем набор результатов преобразуется в объекты строк Python адаптером базы данных с использованием метода fetchmany() определенного в PEP 249.

SQLite может извлекать результаты по частям с помощью fetchmany(), но поскольку SQLite не предоставляет изоляцию между запросами в рамках одного подключения, будьте осторожны при записи в таблицу, по которой происходит итерация. Подробнее см. Изоляция при использовании QuerySet.iterator().

Параметр chunk_size управляет размером порций, которые Django извлекает из драйвера базы данных. Более крупные порции уменьшают нагрузку на общение с драйвером базы данных за счет небольшого увеличения потребления памяти.

До тех пор, пока набор запросов не предварительно выбирает связанные объекты, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявное значение по умолчанию 2000, значение, выведенное из расчета на почтовой рассылке psycopg:

Предполагая строки из 10-20 столбцов с смесью текстовых и числовых данных, 2000 приведет к извлечению менее 100 КБ данных, что кажется хорошим компромиссом между количеством строк, передаваемых, и данными, отброшенными, если цикл завершен преждевременно.

latest()

latest(*fields)
alatest(*fields)

Асинхронная версия: alatest()

Возвращает последний объект в таблице, основанный на заданном поле(ах).

Этот пример возвращает последнюю Entry в таблице в соответствии с полем pub_date:

Entry.objects.latest('pub_date')

Также можно выбрать последний элемент, основываясь на нескольких полях. Например, для выбора записи с самым ранним expire_date в случае, если две записи имеют одинаковое pub_date;

Entry.objects.latest('pub_date', '-expire_date')

Отрицательный знак в '-expire_date' означает сортировку expire_date в убывающем порядке. Поскольку latest() получает последний результат, выбирается Entry с самым ранним expire_date.

Если в метаданных вашей модели задано get_latest_by, вы можете опустить любые аргументы для earliest() или latest(). Поля, указанные в get_latest_by, будут использоваться по умолчанию.

Как и get(), earliest() и latest() генерируют исключение DoesNotExist, если объект с заданными параметрами отсутствует.

Обратите внимание, что earliest() и latest() существуют только для удобства и читаемости.

earliest() и latest() могут возвращать экземпляры с нулевыми датами.

Поскольку сортировка делегирована базе данных, результаты по полям, допускающим нулевые значения, могут сортироваться по-разному, если вы используете разные базы данных. Например, PostgreSQL и MySQL сортируют нулевые значения так, как будто они больше, чем ненулевые значения, в то время как SQLite делает наоборот.

Возможно, вам потребуется отфильтровать нулевые значения:

Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
Изменено в Django 4.1:

alatest() метод был добавлен.

earliest()

earliest(*fields)
aearliest(*fields)

Асинхронная версия: aearliest()

В остальном работает так же, как latest(), за исключением изменения направления.

Изменено в Django 4.1:

aearliest() метод был добавлен.

first()

first()
afirst()

Асинхронная версия: afirst()

Возвращает первый объект, соответствующий запросу, или None , если соответствующего объекта нет. Если у QuerySet нет определённой сортировки, то наборы запросов автоматически сортируются по первичному ключу. Это может повлиять на результаты агрегации, как описано в взаимодействии с order_by().

Пример:

p = Article.objects.order_by('title', 'pub_date').first()

Обратите внимание, что first() — это вспомогательный метод, и приведенный ниже фрагмент кода эквивалентен вышеприведенному примеру:

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None
Изменено в Django 4.1:

afirst() метод был добавлен.

last()

last()
alast()

Асинхронная версия: alast()

Действует как first(), но возвращает последний объект в наборе запросов.

Изменено в Django 4.1:

alast() метод был добавлен.

aggregate()

aggregate(*args, **kwargs)
aaggregate(*args, **kwargs)

Асинхронная версия: aaggregate()

Возвращает словарь агрегированных значений (средних, сумм и т. д.), вычисленных по QuerySet. Каждый аргумент для aggregate() указывает значение, которое будет включено в возвращаемый словарь.

Функции агрегирования, предоставляемые Django, описаны ниже в Функции агрегации. Так как агрегаты также являются выражениями запроса, вы можете объединять агрегаты с другими агрегатами или значениями для создания сложных агрегатов.

Агрегаты, указанные с помощью ключевых аргументов, будут использовать ключевое слово в качестве имени для аннотации. Анонимные аргументы будут иметь имя, сгенерированное на основе имени функции агрегирования и поля модели, которое агрегируется. Сложные агрегаты не могут использовать анонимные аргументы и должны указать ключевое слово в качестве псевдонима.

Например, при работе со статьями блога вы можете узнать количество авторов, которые внесли вклад в статьи блога:

>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}

Используя ключевой аргумент для указания функции агрегирования, вы можете контролировать имя возвращаемого значения агрегирования:

>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}

Более подробное обсуждение агрегации см. в руководстве по теме Агрегации.

Изменено в Django 4.1:

aaggregate() метод был добавлен.

exists()

exists()
aexists()

Асинхронная версия: aexists()

Возвращает True , если QuerySet содержит какие-либо результаты, и False — если нет. Это пытается выполнить запрос наиболее простым и быстрым способом, но фактически выполняет практически такой же запрос, как обычный запрос QuerySet.

exists() полезно для поиска, связанного с существованием каких-либо объектов в QuerySet, особенно в контексте большого QuerySet.

Чтобы проверить, содержит ли набор запросов какие-либо элементы:

if some_queryset.exists():
    print("There is at least one object in some_queryset")

Что будет быстрее, чем:

if some_queryset:
    print("There is at least one object in some_queryset")

…но ненамного (поэтому для получения преимущества по производительности требуется большой набор запросов).

Кроме того, если some_queryset ещё не был оценён, но вы знаете, что он будет оценён в какой-то момент, то использование some_queryset.exists() потребует больше работы в целом (один запрос для проверки существования плюс дополнительный для последующего получения результатов), чем использование bool(some_queryset), которое извлекает результаты, а затем проверяет, были ли возвращены какие-либо.

Изменено в Django 4.1:

aexists() метод был добавлен.

contains()

contains(obj)
acontains(obj)

Асинхронная версия: acontains()

Новое в Django 4.0.

Возвращает True , если QuerySet содержит obj, и False — если нет. Это пытается выполнить запрос наиболее простым и быстрым способом.

contains() полезно для проверки принадлежности объекта к QuerySet, особенно в контексте большого QuerySet.

Чтобы проверить, содержит ли набор запросов определённый элемент:

if some_queryset.contains(obj):
    print('Entry contained in queryset')

Это будет быстрее, чем следующее, которое требует оценки и перебора всего набора запросов:

if obj in some_queryset:
    print('Entry contained in queryset')

Как и в случае с exists(), если some_queryset ещё не был оценён, но вы знаете, что он будет оценён в какой-то момент, то использование some_queryset.contains(obj) выполнит дополнительный запрос к базе данных, что, как правило, приведёт к более медленной общей производительности.

Изменено в Django 4.1:

acontains() метод был добавлен.

update()

update(**kwargs)
aupdate(**kwargs)

Асинхронная версия: aupdate()

Выполняет запрос SQL UPDATE для указанных полей и возвращает количество строк, соответствующих условию (которое может не совпадать с количеством обновленных строк, если некоторые строки уже содержат новое значение).

Например, чтобы отключить комментарии для всех записей блога, опубликованных в 2010 году, можно сделать так:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

(Предполагается, что ваша Entry модель содержит поля pub_date и comments_on.)

Можно обновлять несколько полей — нет ограничений на количество. Например, здесь мы обновляем поля comments_on и headline:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')

Метод update() применяется мгновенно, и единственное ограничение для обновляемого QuerySet состоит в том, что он может обновлять только столбцы в основной таблице модели, а не в связанных моделях. Например, нельзя сделать так:

>>> Entry.objects.update(blog__name='foo') # Won't work!

Однако фильтрация по связанным полям всё ещё возможна:

>>> Entry.objects.filter(blog__id=1).update(comments_on=True)

Нельзя вызвать update() для QuerySet, с которого взята часть или который по каким-либо другим причинам больше нельзя отфильтровать.

Метод update() возвращает количество затронутых строк:

>>> Entry.objects.filter(id=64).update(comments_on=True)
1

>>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
0

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132

Если вы просто обновляете запись и не нуждаетесь в работе с объектом модели, наиболее эффективным способом является вызов update(), а не загрузка объекта модели в память. Например, вместо этого:

e = Entry.objects.get(id=10)
e.comments_on = False
e.save()

…сделайте так:

Entry.objects.filter(id=10).update(comments_on=False)

Использование update() также предотвращает гонку условий, когда что-то может измениться в вашей базе данных в короткий промежуток времени между загрузкой объекта и вызовом save().

Наконец, имейте в виду, что update() выполняет обновление на уровне SQL и, следовательно, не вызывает никаких save() методов для ваших моделей, а также не генерирует сигналы pre_save или post_save (которые являются следствием вызова Model.save()). Если вы хотите обновить множество записей для модели, имеющей пользовательский метод save(), перебирайте их и вызывайте save(), как показано ниже:

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()
Изменено в Django 4.1:

был добавлен метод aupdate().

Упорядоченный запрос

Цепочку order_by() с update() поддерживают только MariaDB и MySQL, а для других баз данных она игнорируется. Это полезно для обновления уникального поля в заданном порядке без конфликтов. Например:

Entry.objects.order_by('-number').update(number=F('number') + 1)

Примечание

Оператор order_by() будет проигнорирован, если он содержит аннотации, унаследованные поля или запросы, охватывающие связи.

Удаление

delete()
adelete()

Асинхронная версия: adelete()

Выполняет запрос SQL DELETE для всех строк в QuerySet и возвращает количество удалённых объектов и словарь с количеством удалений по типу объекта.

delete() применяется мгновенно. Нельзя вызвать delete() для QuerySet, с которого взята часть или который по каким-либо другим причинам больше нельзя отфильтровать.

Например, чтобы удалить все записи в определённом блоге:

>>> b = Blog.objects.get(pk=1)

# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})

По умолчанию, Django’s ForeignKey эмулирует SQL ограничение ON DELETE CASCADE — другими словами, все объекты с внешними ключами, указывающими на объекты, которые будут удалены, будут удалены вместе с ними. Например:

>>> blogs = Blog.objects.all()

# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})

Это поведение каскадного удаления можно настроить с помощью аргумента on_delete к ForeignKey.

Метод delete() выполняет массовое удаление и не вызывает никаких delete() методов для ваших моделей. Однако он генерирует сигналы pre_delete и post_delete для всех удалённых объектов (включая каскадное удаление).

Django необходимо загрузить объекты в память, чтобы отправлять сигналы и обрабатывать каскады. Однако, если нет каскадов и сигналов, Django может использовать быстрый путь и удалить объекты без загрузки в память. Для больших удалений это может значительно уменьшить использование памяти. Также может быть уменьшено количество выполненных запросов.

Внешние ключи, установленные на on_delete DO_NOTHING не препятствуют использованию быстрого пути при удалении.

Обратите внимание, что запросы, генерируемые при удалении объектов, являются деталями реализации и могут быть изменены.

Изменено в Django 4.1:

был добавлен метод adelete().

as_manager()

classmethod as_manager()

Метод класса, возвращающий экземпляр Manager с копией методов QuerySet. Подробнее см. Создание менеджера с методами QuerySet.

Обратите внимание, что в отличие от других пунктов в этом разделе, у него нет асинхронного варианта, так как он не выполняет запрос.

explain()

explain(format=None, **options)
aexplain(format=None, **options)

Асинхронная версия: aexplain()

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

Например, при использовании PostgreSQL:

>>> print(Blog.objects.filter(title='My Blog').explain())
Seq Scan on blog  (cost=0.00..35.50 rows=10 width=12)
  Filter: (title = 'My Blog'::bpchar)

Вывод значительно отличается между базами данных.

explain() поддерживается всеми встроенными бэкендами баз данных, кроме Oracle, так как реализация там не является тривиальной.

Параметр format изменяет формат вывода из значения по умолчанию для баз данных, которое обычно является текстовым. PostgreSQL поддерживает форматы 'TEXT', 'JSON', 'YAML', и 'XML' . MariaDB и MySQL поддерживают форматы 'TEXT' (также называемый 'TRADITIONAL') и 'JSON' . MySQL 8.0.16+ также поддерживает улучшенный формат 'TREE' , который похож на вывод 'TEXT' PostgreSQL и используется по умолчанию, если поддерживается.

Некоторые базы данных принимают флаги, которые могут вернуть больше информации о запросе. Передайте эти флаги в качестве ключевых аргументов. Например, при использовании PostgreSQL:

>>> print(Blog.objects.filter(title='My Blog').explain(verbose=True, analyze=True))
Seq Scan on public.blog  (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
  Output: id, title
  Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms

В некоторых базах данных флаги могут вызвать выполнение запроса, что может оказать неблагоприятное влияние на вашу базу данных. Например, флаг ANALYZE, поддерживаемый MariaDB, MySQL 8.0.18+ и PostgreSQL, может привести к изменениям данных, если существуют триггеры или вызывается функция, даже для запроса SELECT.

Изменено в Django 4.1:

был добавлен метод aexplain().

Field поиски

Поиски по полям — это способ указать основную часть SQL-запроса WHERE . Они задаются в качестве ключевых аргументов для методов QuerySet filter(), exclude() и get().

Для ознакомления см. документацию по моделям и запросам к базе данных.

Встроенные поиски Django перечислены ниже. Также возможно создание пользовательских поисков для полей модели.

Для удобства, если тип поиска не указан (как в Entry.objects.get(id=14)), тип поиска предполагается равным exact.

exact

Точное соответствие. Если предоставленное значение для сравнения — None, оно будет интерпретировано как SQL NULL (подробнее см. isnull).

Примеры:

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

Эквиваленты в SQL:

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

Сравнения MySQL

В MySQL параметр «сопоставление» таблицы базы данных определяет, являются ли сравнения exact чувствительными к регистру. Это параметр базы данных, а не Django. Возможно настроить ваши таблицы MySQL для выполнения сравнений, чувствительных к регистру, но это связано с некоторыми компромиссами. Дополнительную информацию см. в разделе раздел сопоставления документации баз данных.

iexact

Нечувствительное к регистру точное соответствие. Если предоставленное для сравнения значение None, оно будет интерпретироваться как SQL NULL (см. isnull для получения дополнительных сведений).

Пример:

Blog.objects.get(name__iexact='beatles blog')
Blog.objects.get(name__iexact=None)

Эквиваленты SQL:

SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;

Обратите внимание, что первый запрос будет соответствовать 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG', и т. д.

Пользователи SQLite

При использовании бэкэнда SQLite и не-ASCII строк имейте в виду примечание к базе данных о сравнении строк. SQLite не выполняет нечувствительное к регистру сопоставление для не-ASCII строк.

contains

Чувствительное к регистру проверка вхождения.

Пример:

Entry.objects.get(headline__contains='Lennon')

Эквивалент SQL:

SELECT ... WHERE headline LIKE '%Lennon%';

Обратите внимание, что это будет соответствовать заголовку 'Lennon honored today', но не 'lennon honored today'.

Пользователи SQLite

SQLite не поддерживает чувствительные к регистру LIKE операторы; contains ведет себя как icontains для SQLite. Более подробную информацию см. в примечании к базе данных.

icontains

Нечувствительное к регистру проверка вхождения.

Пример:

Entry.objects.get(headline__icontains='Lennon')

Эквивалент SQL:

SELECT ... WHERE headline ILIKE '%Lennon%';

Пользователи SQLite

При использовании бэкэнда SQLite и не-ASCII строк имейте в виду примечание к базе данных о сравнении строк.

in

В заданном итерируемом объекте; часто список, кортеж или набор запросов. Это нетипичный сценарий использования, но строки (являясь итерируемыми) принимаются.

Примеры:

Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')

Эквиваленты SQL:

SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');

Вы также можете использовать набор запросов для динамической оценки списка значений вместо предоставления списка значений:

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

Этот набор запросов будет оценен как подзапрос:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

Если вы передаёте QuerySet в результате values() или values_list() в качестве значения для запроса __in, убедитесь, что из результата извлекается только одно поле. Например, это сработает (фильтрация по именам блогов):

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Этот пример вызовет исключение, так как внутренний запрос пытается извлечь два значения поля, а ожидается только одно:

# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Учитывайте производительность

Будьте осторожны при использовании вложенных запросов и знайте характеристики производительности вашего сервера базы данных (при необходимости, оцените!). Некоторые бэкэнды баз данных, в частности MySQL, не оптимизируют вложенные запросы так хорошо. В таких случаях более эффективно извлечь список значений, а затем передать его во второй запрос. То есть выполнить два запроса вместо одного:

values = Blog.objects.filter(
        name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))

Обратите внимание на list() вызов вокруг Blog QuerySet для принудительного выполнения первого запроса. Без него будет выполнен вложенный запрос, так как наборы запросов ленивы.

gt

Больше чем.

Пример:

Entry.objects.filter(id__gt=4)

Эквивалент SQL:

SELECT ... WHERE id > 4;

gte

Больше или равно.

lt

Меньше чем.

lte

Меньше или равно.

startswith

Чувствительное к регистру начинается с.

Пример:

Entry.objects.filter(headline__startswith='Lennon')

Эквивалент SQL:

SELECT ... WHERE headline LIKE 'Lennon%';

SQLite не поддерживает чувствительные к регистру LIKE операторы; startswith ведет себя как istartswith для SQLite.

istartswith

Нечувствительное к регистру начинается с.

Пример:

Entry.objects.filter(headline__istartswith='Lennon')

Эквивалент SQL:

SELECT ... WHERE headline ILIKE 'Lennon%';

Пользователи SQLite

При использовании бэкэнда SQLite и не-ASCII строк имейте в виду примечание к базе данных о сравнении строк.

endswith

Чувствительное к регистру заканчивается на.

Пример:

Entry.objects.filter(headline__endswith='Lennon')

Эквивалент SQL:

SELECT ... WHERE headline LIKE '%Lennon';

Пользователи SQLite

SQLite не поддерживает чувствительные к регистру LIKE операторы; endswith ведет себя как iendswith для SQLite. Смотрите документацию примечания к базе данных для более подробной информации.

iendswith

Нечувствительное к регистру заканчивается на.

Пример:

Entry.objects.filter(headline__iendswith='Lennon')

Эквивалент SQL:

SELECT ... WHERE headline ILIKE '%Lennon'

Пользователи SQLite

При использовании бэкэнда SQLite и не-ASCII строк имейте в виду примечание к базе данных о сравнении строк.

range

Проверка диапазона (включительно).

Пример:

import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

Эквивалент SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

Вы можете использовать range везде, где можно использовать BETWEEN в SQL — для дат, чисел и даже символов.

Предупреждение

Фильтрация DateTimeField с датами не включит элементы в последний день, поскольку границы интерпретируются как «0:00 в указанную дату». Если pub_date был DateTimeField, указанное выше выражение было бы преобразовано в следующий SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';

Как правило, нельзя смешивать даты и datetime.

date

Для полей datetime преобразует значение как дата. Позволяет цеплять дополнительные запросы к полям. Принимает значение даты.

Пример:

Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

(Для этого запроса не включен фрагмент эквивалентного SQL-кода, потому что реализация соответствующего запроса отличается для различных движков баз данных.)

Когда USE_TZ имеет значение True, поля преобразуются в текущую временную зону перед фильтрацией. Это требует определения временных зон в базе данных.

year

Для полей date и datetime точное соответствие году. Позволяет цеплять дополнительные запросы к полям. Принимает целое число года.

Пример:

Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)

Эквивалент SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';

(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)

Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Это требует определения временных зон в базе данных.

iso_year

Для полей date и datetime точное соответствие году по ISO 8601. Позволяет цеплять дополнительные запросы к полям. Принимает целое число года.

Пример:

Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)

(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)

Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Это требует определения временных зон в базе данных.

month

Для полей date и datetime точное соответствие месяцу. Позволяет цеплять дополнительные запросы к полям. Принимает целое число от 1 (январь) до 12 (декабрь).

Пример:

Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)

Эквивалент SQL:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';

(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)

Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Это требует определения временных зон в базе данных.

day

Для полей date и datetime точное соответствие дню. Позволяет цеплять дополнительные запросы к полям. Принимает целое число дня.

Пример:

Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)

Эквивалент SQL:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';

(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)

Обратите внимание, что это будет соответствовать любой записи с pub_date на третье число месяца, например 3 января, 3 июля и т. д.

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

week

Для полей даты и datetime возвращается номер недели (1-52 или 53) в соответствии с ISO-8601, т.е. недели начинаются с понедельника, а первая неделя содержит первый четверг года.

Пример:

Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)

(Для этого поиска не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса варьируется в зависимости от СУБД.)

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

week_day

Для полей даты и datetime выполняется сопоставление по дню недели. Позволяет цепочку дополнительных поисков по полям.

Принимает целое значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).

Пример:

Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)

(Для этого поиска не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса варьируется в зависимости от СУБД.)

Обратите внимание, что это будет соответствовать любой записи с pub_date, которая попадает на понедельник (день 2 недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются: день 1 - воскресенье, день 7 - суббота.

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

iso_week_day

Для полей даты и datetime выполняется точное сопоставление дня недели по ISO 8601. Позволяет цепочку дополнительных поисков по полям.

Принимает целое значение, представляющее день недели от 1 (понедельник) до 7 (воскресенье).

Пример:

Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)

(Для этого поиска не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса варьируется в зависимости от СУБД.)

Обратите внимание, что это будет соответствовать любой записи с pub_date, которая попадает на понедельник (день 1 недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются: день 1 - понедельник, день 7 - воскресенье.

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

quarter

Для полей даты и datetime выполняется сопоставление по кварталу года. Позволяет цепочку дополнительных поисков по полям. Принимает целое значение от 1 до 4, представляющее квартал года.

Пример для получения записей во втором квартале (с 1 апреля по 30 июня):

Entry.objects.filter(pub_date__quarter=2)

(Для этого поиска не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса варьируется в зависимости от СУБД.)

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

time

Для полей datetime преобразует значение к типу времени. Позволяет цепочку дополнительных поисков по полям. Принимает значение datetime.time.

Пример:

Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))

(Для этого поиска не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса варьируется в зависимости от СУБД.)

Когда USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

hour

Для полей datetime и time, точное соответствие часу. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 23.

Пример:

Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)

Эквивалент SQL:

SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';

(Точный синтаксис SQL зависит от СУБД.)

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

minute

Для полей datetime и time, точное соответствие минуте. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 59.

Пример:

Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)

Эквивалент SQL:

SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';

(Точный синтаксис SQL зависит от СУБД.)

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

second

Для полей datetime и time, точное соответствие секунде. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 59.

Пример:

Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)

Эквивалент SQL:

SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';

(Точный синтаксис SQL зависит от СУБД.)

Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.

isnull

Принимает True или False, соответствующие SQL-запросам IS NULL и IS NOT NULL соответственно.

Пример:

Entry.objects.filter(pub_date__isnull=True)

Эквивалент SQL:

SELECT ... WHERE pub_date IS NULL;

regex

Чувствительное к регистру сопоставление по регулярному выражению.

Синтаксис регулярного выражения соответствует синтаксису используемого СУБД. В случае SQLite, не имеющем встроенной поддержки регулярных выражений, эта функция предоставляется пользовательской функцией REGEXP (на Python), и синтаксис регулярных выражений, следовательно, соответствует синтаксису модуля re Python.

Пример:

Entry.objects.get(title__regex=r'^(An?|The) +')

Эквиваленты SQL:

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

Рекомендуется использовать сырые строки (например, r'foo' вместо 'foo') для передачи синтаксиса регулярного выражения.

iregex

Нечувствительное к регистру сопоставление по регулярному выражению.

Пример:

Entry.objects.get(title__iregex=r'^(an?|the) +')

Эквиваленты SQL:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

Функции агрегации

Django предоставляет следующие функции агрегации в модуле django.db.models. Подробности по использованию этих функций агрегации см. в руководстве по агрегации. См. документацию по Aggregate, чтобы узнать, как создавать свои агрегаты.

Предупреждение

SQLite не может обрабатывать агрегацию по полям даты/времени в режиме «из коробки». Это связано с тем, что в SQLite нет встроенных полей даты/времени, и Django в настоящее время эмулирует эти возможности с использованием текстового поля. Попытки использовать агрегацию по полям даты/времени в SQLite приведут к ошибке NotSupportedError.

Примечание

Функции агрегации возвращают None при использовании с пустым QuerySet. Например, функция агрегации Sum возвращает None вместо 0, если QuerySet не содержит записей. Чтобы вернуть другое значение вместо этого, передайте значение аргументу default. Исключением является Count, которое возвращает 0 , если QuerySet пусто. Count не поддерживает аргумент default.

У всех агрегатов есть общие параметры:

expressions

Строки, которые ссылаются на поля модели, преобразования поля или выражения запроса.

output_field

Необязательный аргумент, представляющий поле модели возвращаемого значения.

Примечание

При объединении нескольких типов полей Django может определить тип output_field только если все поля имеют одинаковый тип. В противном случае вы должны предоставить output_field самостоятельно.

filter

Необязательный Q object, используемый для фильтрации строк, которые агрегируются.

См. Условную агрегацию и Фильтрацию по аннотациям для примеров использования.

default

Новое в Django 4.0.

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

**extra

Ключевые аргументы, которые могут предоставить дополнительный контекст для SQL, сгенерированного агрегацией.

Avg

class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)

Возвращает среднее значение заданного выражения, которое должно быть числовым, если вы не укажете другой output_field.

  • Значение по умолчанию для псевдонима: <field>__avg
  • Тип возвращаемого значения: float если входной параметр int, в противном случае — такое же, как поле ввода, или output_field если предоставлено
distinct

Необязательно. Если distinct=True, Avg возвращает среднее значение уникальных значений. Это SQL-эквивалент AVG(DISTINCT <field>). Значение по умолчанию False.

Count

class Count(expression, distinct=False, filter=None, **extra)

Возвращает количество объектов, связанных через предоставленное выражение.

  • Значение по умолчанию для псевдонима: <field>__count
  • Тип возвращаемого значения: int
distinct

Необязательно. Если distinct=True, подсчёт будет включать только уникальные экземпляры. Это SQL-эквивалент COUNT(DISTINCT <field>). Значение по умолчанию False.

Примечание

Аргумент default не поддерживается.

Max

class Max(expression, output_field=None, filter=None, default=None, **extra)

Возвращает максимальное значение заданного выражения.

  • Значение по умолчанию для псевдонима: <field>__max
  • Тип возвращаемого значения: такой же, как поле ввода, или output_field если предоставлено

Min

class Min(expression, output_field=None, filter=None, default=None, **extra)

Возвращает минимальное значение заданного выражения.

  • Значение по умолчанию для псевдонима: <field>__min
  • Тип возвращаемого значения: такой же, как поле ввода, или output_field если предоставлено

StdDev

class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)

Возвращает стандартное отклонение данных в заданном выражении.

  • Значение по умолчанию для псевдонима: <field>__stddev
  • Тип возвращаемого значения: float если входной параметр int, в противном случае — такое же, как поле ввода, или output_field если предоставлено
sample

Необязательно. По умолчанию StdDev возвращает стандартное отклонение генеральной совокупности. Однако, если sample=True, значение возврата будет стандартным отклонением выборки.

Sum

class Sum(expression, output_field=None, distinct=False, filter=None, default=None, **extra)

Вычисляет сумму всех значений заданного выражения.

  • Значение по умолчанию для псевдонима: <field>__sum
  • Тип возвращаемого значения: такой же, как поле ввода, или output_field если предоставлено
distinct

Необязательно. Если distinct=True, Sum возвращает сумму уникальных значений. Это SQL-эквивалент SUM(DISTINCT <field>). Значение по умолчанию False.

Variance

class Variance(expression, output_field=None, sample=False, filter=None, default=None, **extra)

Возвращает дисперсию данных в заданном выражении.

  • Значение по умолчанию для псевдонима: <field>__variance
  • Тип возвращаемого значения: float если входной параметр int, в противном случае — такое же, как поле ввода, или output_field если предоставлено
sample

Необязательно. По умолчанию Variance возвращает дисперсию генеральной совокупности. Однако, если sample=True, значение возврата будет дисперсией выборки.

Инструменты, связанные с запросами

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

Q() объекты

class Q

Объект Q() представляет собой SQL-условие, которое может быть использовано в операциях, связанных с базой данных. Он похож на то, как объект F() представляет значение поля модели или аннотации. Они позволяют определить и повторно использовать условия, а также комбинировать их с операторами, такими как | (OR), & (AND) и ^ (XOR). См. Сложные запросы с объектами Q.

Изменено в Django 4.1:

Добавлена поддержка оператора ^ (XOR).

Prefetch() объекты

class Prefetch(lookup, queryset=None, to_attr=None)

Объект Prefetch() может быть использован для управления работой prefetch_related().

Аргумент lookup описывает отношения, которые необходимо отслеживать, и работает так же, как строковые запросы, передаваемые prefetch_related(). Например:

>>> from django.db.models import Prefetch
>>> Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch('choice_set'))
<QuerySet [<Question: What's up?>]>

Аргумент queryset предоставляет базовый QuerySet для данного запроса. Это полезно для дальнейшего фильтрации операции предварительной выборки или вызова select_related() из предварительно выбранного отношения, что ещё больше уменьшает количество запросов:

>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
<QuerySet [<Choice: The sky>]>
>>> prefetch = Prefetch('choice_set', queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: The sky>]>

Аргумент to_attr устанавливает результат операции предварительной выборки в пользовательское свойство:

>>> prefetch = Prefetch('choice_set', queryset=voted_choices, to_attr='voted_choices')
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
[<Choice: The sky>]
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

Примечание

При использовании to_attr результат предварительной выборки хранится в списке. Это может значительно повысить скорость по сравнению с традиционными вызовами prefetch_related , которые сохраняют кэшированный результат внутри экземпляра QuerySet.

prefetch_related_objects()

prefetch_related_objects(model_instances, *related_lookups)

Предварительно выбирает заданные запросы по итерируемому набору экземпляров модели. Это полезно в коде, который получает список экземпляров модели, а не QuerySet; например, при извлечении моделей из кэша или их ручном создании.

Передайте итерируемый набор экземпляров модели (все они должны быть одного класса) и запросы или объекты Prefetch, которые вы хотите предварительно выбрать. Например:

>>> from django.db.models import prefetch_related_objects
>>> restaurants = fetch_top_restaurants_from_cache()  # A list of Restaurants
>>> prefetch_related_objects(restaurants, 'pizzas__toppings')

При использовании нескольких баз данных с prefetch_related_objects, запрос предварительной выборки будет использовать базу данных, связанную с экземпляром модели. Это можно переопределить, используя пользовательский набор запросов в связанном запросе.

FilteredRelation() объекты

class FilteredRelation(relation_name, *, condition=Q())
relation_name

Имя поля, по которому вы хотите отфильтровать отношение.

condition

Объект Q для управления фильтрованием.

FilteredRelation используется с annotate() для создания ON условия при выполнении JOIN. Он не действует на стандартное отношение, а на имя аннотации (pizzas_vegetarian в примере ниже).

Например, чтобы найти рестораны, у которых есть вегетарианские пиццы с 'mozzarella' в названии:

>>> from django.db.models import FilteredRelation, Q
>>> Restaurant.objects.annotate(
...    pizzas_vegetarian=FilteredRelation(
...        'pizzas', condition=Q(pizzas__vegetarian=True),
...    ),
... ).filter(pizzas_vegetarian__name__icontains='mozzarella')

Если пицц большое количество, этот набор запросов работает лучше, чем:

>>> Restaurant.objects.filter(
...     pizzas__vegetarian=True,
...     pizzas__name__icontains='mozzarella',
... )

потому что фильтрация в WHERE разделе первого набора запросов будет работать только с вегетарианскими пиццами.

FilteredRelation не поддерживает:

  • QuerySet.only() и prefetch_related().
  • Наследованное от родительской модели GenericForeignKey.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.1/ref/models/querysets/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API