• 3.1
  • 3.2
  • 5.0
  • Версия документации: 6.1

QuerySet API

Этот раздел описывает QuerySet API. Изложенный материал опирается на материал, изложенный в разделах о моделях и выполнении запросов, возможно вам следует прочитать их перед прочтением этого раздела.

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

Когда вычисляется QuerySets

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)
    

    И синхронные, и асинхронные итераторы QuerySets используют один и тот же базовый кеш.

  • Ограничение выборки. Как описано в Ограничение выборки, выборка QuerySet может быть ограничена, используя синтаксис срезов в Python. Срез не вычисленного QuerySet обычно возвращает новый не вычисленный QuerySet, но Django выполнит запрос, если будет указан шаг среза и вернет список. Срез QuerySet, который был вычислен(частично или полностью), также вернет список.

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

  • Pickling/кэширование. Смотрите соответствующий раздел о pickling QuerySets. Основное замечание это то, что при этих операциях будет выполнен запрос к базе данных.

  • repr(). QuerySet будет вычислен при вызове repr(). Это сделано для удобства использования в консоли Python, вы можете сразу увидеть результат работая с QuerySet в консоли.

  • len(). QuerySet будет вычислен при выполнении len() над ним. Как вы и ожидаете будет возвращено количество объектов в результате выборки.

    Заметка: Не используйте len() с QuerySet если вам нужно узнать только количество записей в выборке. Эффективнее использовать подсчет на уровне базы данных, используя оператор 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().

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

Используя 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, и является частью внутреннего механизма создания запросов. Однако, поддерживает использование pickle и unpickle как показано в примере выше.

Ограничения на 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'}]>

нельзя переносить «pickles» между версиями

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

Так как ошибки совместимости «pickle» тяжело диагностировать, если вы попытаетесь распаковать 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() или порядок по умолчанию в модели. Ложь в противном случае.

db

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

Примечание

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

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

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

Примечание

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

filter

filter(*args, **kwargs)

Возвращает новый QuerySet содержащий объекты отвечающие параметрам фильтрации.

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

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

exclude

exclude(*args, **kwargs)

Возвращает новый QuerySet содержащий объекты не отвечающие параметрам фильтрации.

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

Этот пример исключает все записи с pub_date раньше 3.01.2005 И с 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 раньше 3.01.2005 ИЛИ с headline равным «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 (*args).

annotate

annotate(*args, **kwargs)

Аннотирует каждый объект в QuerySet предоставленным списком выражений запроса или Q объектов. Каждый объект может быть аннотирован с помощью:

  • простое значение через Value();

  • ссылка на поле модели (или любых связанных моделей) через F();

  • логическое значение через Q(); или

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

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

Функции агрегации описаны в соответствующем разделе ниже.

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

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

>>> 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

Модель «Блог» не определяет атрибут «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(*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 модели. Вы можете переопределить сортировку используя метод 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, если сортировка была применена для QuerySet каким-либо образом.

Каждый последующий вызов 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() будет добавлено в список выбираемых колонок в части SELECT SQL запроса. Это может привести к непредвиденным результатам если вы используете distinct(). При сортировке по колонке из связанной таблицы, эти колонки будет включены в список выбираемых колонок, что может сделать одинаковые строки результата уникальными. Т.к. эти дополнительные колонки не будет включены в результат(они используются только для определения сортировки), будет выглядеть так, вроде бы distinct() возвращает не уникальные элементы результатов.

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

Мораль здесь в том, что если вы используете distinct(), будьте осторожны с упорядочиванием по связанным моделям. Аналогично, при совместном использовании distinct() и values() будьте осторожны при упорядочивании по полям, не входящим в вызов values().

Только для PostgreSQL можно указать позиционный аргумент (*fields) определяющий для каких полей применять DISTINCT. Они будут добавлены в SELECT DISTINCT ON часть SQL запроса. Вот в чем разница. При обычном вызове 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() используется сортировку, которая указана в связанной модели. Возможно вам понадобится явно отсортировать по внешнему ключу, или полю связанной модели, чтобы 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() также принимает необязательные аргументы ключевых слов, **выражения, которые передаются в 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() после вызова :meth:extra, любые поля, определенные аргументом select в :meth: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 ключевые преобразования.

Changed in Django 5.2:

Предложение SELECT, созданное при использовании values(), было обновлено для соблюдения порядка указанных *полей и **выражений.

values_list

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

Это похоже на values(), за исключением того, что вместо возврата словарей он возвращает кортежи при повторении. Каждый кортеж содержит значение из соответствующего поля или выражения, переданного в вызов value_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, это будет означать, что возвращаемые результаты представляют собой одиночные значения, а не кортежи из 1 единицы. Пример должен прояснить разницу:

>>> 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)]>

Авторы с несколькими записями появляются несколько раз, а у авторов без записей в заголовке записи указано «Нет».

Аналогично, при запросе обратного внешнего ключа для записей, не имеющих автора, отображается «Нет»:

>>> 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 ключевые преобразования.

Changed in Django 5.2:

Предложение SELECT, созданное при использовании values_list(), было обновлено для соблюдения порядка указанных *полей.

dates

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

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

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

  • "year" возвращает список уникальных значений года из всех дат указанного поля.

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

  • "year" возвращает список уникальных значений года из всех дат указанного поля.

  • "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)

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

field_name – название поля модели типа DateTimeField.

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

order – сортировка значений. По-умолчанию 'ASC', должна быть 'ASC' или 'DESC'.

tzinfo указывает часовой пояс используемый при создании объектов datetime. Принимает объект datetime.tzinfo. Если передать None, Django использует текущий часовой пояс. Не используется при USE_TZ равном False.

Примечание

Функция выполняет преобразование даты на уровне базы данных. Поэтому ваша база данных должна понимать значение вида tzinfo.tzname(None). Для этого необходимо:

  • SQLite: нет требований. Преобразования выполняются в Python.

  • PostgreSQL: нет дополнительных требований (смотрите Time Zones).

  • Oracle: нет дополнительных требований (смотрите Choosing a Time Zone File).

  • MySQL: установите pytz_ и загрузите таблицы часовых поясов с помощью mysql_tzinfo_to_sql.

нет()

none()

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

Например:

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

все()

all()

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

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

using

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")

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

iterator

intersection(*other_qs)

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

>>> qs1.intersection(qs2, qs3)

См. некоторые ограничения в union().

defer

difference(*other_qs)

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

>>> qs1.difference(qs2, qs3)

См. некоторые ограничения в union().

**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.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. Этот пример уязвим для SQL-инъекций из-за кавычек вокруг %s:

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

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

По определению, дополнительные параметры поиска определенные в extra() не переносимы между различными типами данных(потому что вы используете непосредственно 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;
    

    Обратите внимание, что круглые скобки, необходимые для большинства СУБД вокруг подзапросов, не требуются в предложениях Django select.

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

    Например:

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

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

  • where / tables

    Вы можете добавить оператор SQL WHERE — возможно для выполнения не явного объединения таблиц — by using where. Используя параметр tables можно добавить таблицы в оператор SQL FROM.

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

    Например:

    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 таблиц, которые уже используются запросом. В таком случае Django предполагает, что вы хотите добавить их повторно. Это создает проблему, т.к. таблица будет добавлена с псевдонимом(an alias). Если таблица несколько раз используется в запросе, второй и последующие вхождения должны использовать псевдонимы, чтобы база данных могла различить их. При обращении к добавленной таблице в параметре where вы получите ошибку.

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

  • order_by

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

    Например:

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

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

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

  • params

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

    Например:

    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 преобразует все значения поля в число перед сравнением. Например, если таблица содержит значения 'abc', 'def' и в запросе WHERE mycolumn=0, обе строки попадут в результат. Чтобы избежать этого, используйте значение правильного типа в запросе.

defer

defer(*fields)

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

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

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

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

Примечание

Отложенные поля не будут выполнять ленивую загрузку из асинхронного кода. Вместо этого вы получите исключение 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()), включающий аргумент из агрегации (например, использование результата annotate()), не имеет смысла: это вызовет исключение. Агрегированные значения всегда будут извлекаться в результирующий набор запросов.

Примечание

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

Даже если вы считаете, что находитесь в ситуации расширенного использования, используйте defer() только когда вы не можете во время загрузки набора запросов определить, потребуются ли вам дополнительные поля или нет. Если вы часто загружаете и используете определенное подмножество своих данных, лучший выбор, который вы можете сделать, — это нормализовать ваши модели и поместить незагруженные данные в отдельную модель (и таблицу базы данных). Если по какой-то причине столбцы должны оставаться в одной таблице, создайте модель с Meta.managed = False (см. документацию по атрибуту managed), содержащую только те поля, которые вам обычно необходимо загружать, и используйте ее там, где в противном случае вы могли бы вызвать 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(*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 immediately.
Entry.objects.defer("body").only("headline", "body")

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

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

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

Примечание

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

Примечание

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

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)

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

Например:

from django.db import transaction

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

Все, удовлетворяющие фильтрам, строки будут заблокированы до завершения транзакции, то есть другие транзакции не смогут изменить или заблокировать это строки.

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

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

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

Если вы хотите заблокировать родительские модели при использовании многотабличного наследования <multi-table-inheritance>`, вы должны указать поля родительских ссылок (по умолчанию <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() для отношений, допускающих значение NULL:

>>> 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 поддерживает аргументы 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.

сырой()

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

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

Смотрите Использование чистого SQL.

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

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

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

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

И (&)

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

Можно использовать такой запрос:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1).filter(y=2)

Аналог SQL:

SELECT ... WHERE x=1 AND 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

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

Исключающее ИЛИ (^)

Объединяет два набора QuerySet с помощью оператора SQL XOR. Выражение 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=MOD(
    (CASE WHEN x THEN 1 ELSE 0 END) +
    (CASE WHEN y THEN 1 ELSE 0 END) +
    ...
    (CASE WHEN z THEN 1 ELSE 0 END),
    2
)

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

Следующие методы выполняют QuerySet и возвращают не QuerySet.

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

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

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

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.")

create

create(**kwargs)
acreate(**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 т.к. первичный ключ должен быть уникальным. Будьте готовы обработать исключение, если вы самостоятельно указываете первичный ключ.

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()

Такой способ становится весьма громоздким при увеличении количества полей модели. Пример выше может быть переписан с использованием метода 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), этот метод склонен к «гонке-состояний» и в БД могут попасть не уникальные данные(прим. пер. - Django то проверить уникальность, но при нескольких процессах запросы могут одновременно отправиться на выполнения к БД, а там уже ничего не проверяется).

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

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()кроме одного не обязательного defaults — будут использованы при вызове get(). Если объект найден, get_or_create() вернет этот объект и False. Если найдено несколько объектов - будет вызвано исключение 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 и вы хотите использовать его в параметрах поиска в 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 должно быть уникальным.

update_or_create

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

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

Удобный метод обновления объекта с заданными «кваргами» и создания нового при необходимости. Оба create_defaults и defaults являются словарями пар (поле, значение). Значения в create_defaults и defaults могут быть вызываемыми. defaults используется для обновления объекта, а create_defaults используется для операции создания. Если create_defaults не указан, defaults будет использоваться для операции создания.

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

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

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

defaults = {"first_name": "Bob"}
create_defaults = {"first_name": "Bob", "birthday": date(1940, 10, 9)}
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(create_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"},
    create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)

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

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

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

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 не будут вызваны.

  • Не работает с дочерними моделями при multi-table наследовании.

  • Если первичный ключ модели представляет собой AutoField или имеет значение db_default, а ignore_conflicts имеет значение False, атрибут первичного ключа можно получить только в определенных базах данных (в настоящее время PostgreSQL, MariaDB и 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 и Oracle ограничивают количество параметров в запросе.)

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

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

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

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

В MySQL и MariaDB установка параметра «ignore_conflicts» в значение «True» превращает определенные типы ошибок, кроме дублирующегося ключа, в предупреждения. Даже в строгом режиме. Например: недопустимые значения или нарушения, не допускающие значения NULL. Дополнительную информацию см. в документации MySQL и документации MariaDB.

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

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

  • Вы не можете обновить первичный ключ модели.

  • Метод модели save() не будет вызван, и сигналы pre_save и post_save не будут вызваны.

  • При обновлении большого количества столбцов в большом количестве строк сгенерированный SQL может быть очень большим. Избегайте этого, указав подходящий batch_size.

  • При обновлении большого количества объектов имейте в виду, что Bulk_update() подготавливает все предложения WHEN для каждого объекта во всех пакетах перед выполнением каких-либо запросов. Это может потребовать больше памяти, чем ожидалось. Чтобы уменьшить использование памяти, вы можете использовать такой подход:

    from itertools import islice
    
    batch_size = 100
    ids_iter = range(1000)
    while ids := list(islice(ids_iter, batch_size)):
        batch = Entry.objects.filter(ids__in=ids)
        for entry in batch:
            entry.headline = f"Updated headline {entry.pk}"
        Entry.objects.bulk_update(batch, ["headline"], batch_size=batch_size)
    
  • Обновление полей, определенных в предках многотабличного наследования, потребует дополнительного запроса для каждого предка.

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

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

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

count

count()
acount()

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

Возвращает количество записей в базе данных отвечающем запросу QuerySet. Метод count() никогда не вызывает исключение.

Например:

# 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() будет использовать эту длину, а не выполнять дополнительный запрос к базе данных.

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() пустого списка будет получен пустой словарь.

iterator

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

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

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

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

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

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

В некоторых базах данных (например, Oracle, SQLite <https://www.sqlite.org/limits.html#max_variable_number>`_) максимальное количество терминов в предложении SQL ``IN может быть ограничено. Следовательно, следует использовать значения ниже этого предела. (В частности, при предварительной выборке по двум или более отношениям размер фрагмента должен быть достаточно мал, чтобы ожидаемое количество результатов для каждого предварительно выбранного отношения все еще оставалось ниже предела.)

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

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

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

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

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

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

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

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

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

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

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

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

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

latest

latest(*fields)
alatest(*fields)

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

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

Этот пример возвращает последний объект 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.

Если в Meta модели определен get_latest_by, вы можете не указывать аргумент field_name при вызове earliest() или latest(). Django будет использовать поле указанное в get_latest_by как значение по-умолчанию.

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

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

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

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

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

Entry.objects.filter(pub_date__isnull=False).latest("pub_date")

earliest

earliest(*fields)
aearliest(*fields)

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

Работает как и latest() только наоборот.

first

first()
afirst()

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

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

Например:

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

first() создан просто для удобства и аналогичен следующему коду:

try:
    p = Article.objects.order_by("title", "pub_date")[0]
except IndexError:
    p = None

последний()

last()
alast()

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

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

aggregate

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

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

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

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

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

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

>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry__authors"))
{'entry__authors__count': 16}

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

>>> Blog.objects.aggregate(number_of_authors=Count("entry__authors"))
{'number_of_authors': 16}

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

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_query_set.exists() выполнит больше работы (один запрос для проверки наличия данных и один для получения данных) чем просто bool(some_queryset), который получит результат и проверит не пустой ли он.

содержит()

contains(obj)
acontains(obj)

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

Возвращает 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) выполнит дополнительный запрос к базе данных, что обычно приводит к снижению общей производительности.

update

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

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

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

Например, чтобы отключить комментарии для всех записей блога, опубликованных в 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().

MySQL не поддерживает обновления самостоятельного выбора

В MySQL QuerySet.update() может выполнить SELECT, за которым следует UPDATE, вместо одного UPDATE при фильтрации связанных таблиц, что может привести к возникновению состояния гонки, если между запросами происходят одновременные изменения. Чтобы обеспечить атомарность, рассмотрите возможность использования транзакций или избегайте таких условий фильтрации в MySQL.

Наконец, помните, что 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()
Упорядоченный набор запросов

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

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

Примечание

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

delete()

delete()
adelete()

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

Выполняет SQL запрос для удаления записей в 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})

По умолчанию ForeignKey в Django эмулирует ограничение 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.

as_manager

classmethod as_manager()

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

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

**extra

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 поддерживают форматы «ТЕКСТ» (также называемый «ТРАДИЦИОННЫЙ») и «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.

Changed in Django 5.2:

Была добавлена ​​поддержка опций memory и serialize в PostgreSQL 17+.

Операторы фильтрации

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

Введение смотрите в разделе о моделях и выполнении запросов к базе данных.

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

По умолчанию, если тип фильтра явно не указан (например, Entry.objects.get(id=14)), подразумевается exact.

select

Точное совпадение. Если передано значение 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, настройка «collation» таблицы базы данных определяет будет ли использовано регистрозависимое сравнение для 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 и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite. SQLite не выполняет регистронезависимое сравнение Unicode строк.

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. Смотрите замечание о сравнении строк в SQLite.

icontains

Регистронезависимая проверка на вхождение.

Например:

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

Аналог SQL:

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

Пользователям SQLite

Используя SQLite и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite.

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');

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

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() с первым QuerySet, чтобы спровоцировать выполнение запроса. Без этого, он будет использован как подзапрос т.к. QuerySets – ленивы.

гт

Больше чем.

Например:

Entry.objects.filter(id__gt=4)

Аналог SQL:

SELECT ... WHERE id > 4;

гте

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

л

Меньше чем.

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 и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite.

endswith

Регистрозависимая проверка оканчивается ли поле с указанного значения.

Например:

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

Аналог SQL:

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

Пользователям SQLite

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

iendswith

Регистронезависимая проверка оканчивается ли поле с указанного значения.

Например:

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

Аналог SQL:

SELECT ... WHERE headline ILIKE '%Lennon'

Пользователям SQLite

Используя SQLite и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite.

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 по датам не включит записи последнего дня, так как границы интерпретируются как «00:00 указанного дня». Если pub_date было DateTimeField, мы бы получили следующий SQL запрос:

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

В общем вы не можете использовать date и datetime вместе.

date

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

Например:

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, значение поля datetime будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

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 будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

year

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

Например:

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 будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

день

Проверка дня месяца для полей 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-го января, 3-го июля и тд.

При USE_TZ равном True, значение поля datetime будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

week_day

Для полей даты и даты и времени верните номер недели (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

Проверка дня недели для полей date/datetime. Позволяет использовать дополнительные проверки поля.

Принимает номер дня недели от 1 (воскресение) до 7 (суббота).

Например:

Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)

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

Будут найдены записи, у которых дата в pub_date – понедельник (второй день недели), независимо от месяца и года. Дни недели пронумерованы от 1(воскресение) до 7(суббота).

При USE_TZ равном True, значение поля datetime будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

iso_week_day

Для полей даты и даты и времени точное соответствие дня недели 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 — понедельник, день 7 — воскресенье.

При USE_TZ равном True, значение поля datetime будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

четверть

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

Пример получения записей за второй квартал (с 1 апреля по 30 июня):

Entry.objects.filter(pub_date__quarter=2)

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

При USE_TZ равном True, значение поля datetime будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

datetimes

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

Например:

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, значение поля datetime будет преобразовано в текущий часовой пояс. Для этого необходимо настроить часовые пояса для базы данных.

hour

Проверка часа для полей date/datetime. Позволяет использовать дополнительные проверки поля. Принимает число от 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

Проверка минуты для полей date/datetime. Позволяет использовать дополнительные проверки поля. Принимает целое число от 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

Проверка секунды для полей date/datetime. Позволяет использовать дополнительные проверки поля. Принимает целое число от 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, который не поддерживает регулярные выражения, эта функция обеспечена на уровне Python, поэтому используется синтаксис модуля Python re.

Например:

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

Рекомендуется использовать «raw» строки (например, 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 не содержит записей или для любой пустой группы в непустом QuerySet. Чтобы вместо этого вернуть другое значение, определите аргумент default. Count является исключением из этого поведения; он возвращает 0, если QuerySet пуст, поскольку Count не поддерживает аргумент default.

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

expression

Строки, ссылающиеся на поля модели, преобразования поля или выражения запроса.

output_field

Необязательный аргумент, который определяет поле модели результата.

Примечание

При использовании нескольких полей Django может определить output_field в том случае, если все поля одного типа. Иначе необходимо явно указать output_field.

filter

Необязательный Q-объект, который используется для фильтрации агрегируемых строк.

См. примеры использования в условной агрегации и фильтрации по аннотациям.

default

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

**extra

Именованные аргументы, которая указывают дополнительный контекст для SQL, созданного для агрегации.

ЛюбоеЗначение

New in Django 6.0.
class AnyValue(expression, output_field=None, filter=None, default=None, **extra)

Возвращает произвольное значение из ненулевых входных значений.

  • Псевдоним по умолчанию: <field>__anyvalue

  • Тип возвращаемого значения: такой же, как поле ввода, или «поле вывода», если оно указано. Если набор запросов или группировка пусты, возвращается default.

Пример использования:

>>> # Get average rating for each year along with a sample headline
>>> # from that year.
>>> from django.db.models import AnyValue, Avg, F, Q
>>> sample_headline = AnyValue("headline")
>>> Entry.objects.values(
...     pub_year=F("pub_date__year"),
... ).annotate(
...     avg_rating=Avg("rating"),
...     sample_headline=sample_headline,
... )

>>> # Get a sample headline from each year with rating greater than 4.5.
>>> sample_headline = AnyValue(
...     "headline",
...     filter=Q(rating__gt=4.5),
... )
>>> Entry.objects.values(
...     pub_year=F("pub_date__year"),
... ).annotate(
...     avg_rating=Avg("rating"),
...     sample_headline=sample_headline,
... )

Поддерживается в SQLite, MySQL, Oracle и PostgreSQL 16+.

MySQL с включенной ONLY_FULL_GROUP_BY

Когда в MySQL включен режим SQL ONLY_FULL_GROUP_BY, может возникнуть необходимость использовать AnyValue, если агрегация включает в себя сочетание агрегатных и неагрегированных функций. Использование AnyValue позволяет ссылаться на неагрегирующую функцию в списке выбора, когда база данных не может определить, что она функционально зависит от столбцов в предложении group by. Дополнительную информацию см. в документации по агрегации <aggregation-mysql-only-full-group-by>`.

Среднее

class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)

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

  • Псевдоним по-умолчанию: <field>__avg

  • Тип возвращаемого значения: float, если входное значение int, в противном случае то же, что и поле ввода, или output_field, если оно указано. Если набор запросов или группировка пусты, возвращается default.

distinct

Необязательный. Если distinct=True, Avg возвращает среднее значение уникальных значений. Это SQL-эквивалент AVG(DISTINCT <field>). Значение по умолчанию — «False».

Count

class Count(expression, distinct=False, filter=None, **extra)

Возвращает количество объектов, связанных указанным выражением. Count('*') эквивалентно выражению SQL COUNT(*).

  • Псевдоним по-умолчанию: <field>__count

  • Тип возвращаемого значения: int

distinct

Необязательный. Если distinct=True, счетчик будет включать только уникальные экземпляры. Это SQL-эквивалент COUNT(DISTINCT <поле>). Значение по умолчанию — «False».

Примечание

Аргумент default не поддерживается.

Макс

class Max(expression, output_field=None, filter=None, default=None, **extra)

Возвращает максимальное значение указанного выражения.

  • Псевдоним по-умолчанию: <field>__max

  • Тип возвращаемого значения: такой же, как поле ввода, или «поле вывода», если оно указано. Если набор запросов или группировка пусты, возвращается default.

Мин

class Min(expression, output_field=None, filter=None, default=None, **extra)

Возвращает минимальное значение указанного выражения.

  • Псевдоним по-умолчанию: <field>__min

  • Тип возвращаемого значения: такой же, как поле ввода, или «поле вывода», если оно указано. Если набор запросов или группировка пусты, возвращается default.

StdDev

class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)

Возвращает стандартное отклонение для данных указанного выражения.

  • Псевдоним по-умолчанию: <field>__stddev

  • Тип возвращаемого значения: float, если входное значение int, в противном случае то же, что и поле ввода, или output_field, если оно указано. Если набор запросов или группировка пусты, возвращается default.

sample

Необязательный. По умолчанию StdDev возвращает стандартное отклонение генеральной совокупности. Однако, если sample=True, возвращаемое значение будет стандартным отклонением выборки.

Сумма

class Sum(expression, output_field=None, distinct=False, filter=None, default=None, **extra)

Возвращает сумму всех значений указанного выражения.

  • Псевдоним по-умолчанию: <field>__sum

  • Тип возвращаемого значения: такой же, как поле ввода, или «поле вывода», если оно указано. Если набор запросов или группировка пусты, возвращается default.

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, если оно указано. Если набор запросов или группировка пусты, возвращается default.

sample

Необязательный. По умолчанию Variance возвращает дисперсию генеральной совокупности. Однако, если sample=True, возвращаемым значением будет выборочная дисперсия.

StringAgg

New in Django 6.0.
class StringAgg(expression, delimiter, output_field=None, distinct=False, filter=None, order_by=None, default=None, **extra)

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

  • Псевдоним по умолчанию: <field>__stringagg

  • Тип возвращаемого значения: строка или выходное_поле, если указано. Если набор запросов или группировка пусты, возвращается default.

delimiter

Значение или выражение, представляющее строку, которая должна разделять каждое из значений. Например, Значение(",").

Back to Top