Справочник по API QuerySet
В этом документе описываются детали API QuerySet. Он базируется на материалах, представленных в руководствах по моделям и запросам к базе данных, поэтому, вероятно, вам стоит ознакомиться с этими документами перед чтением этого.
В этом справочнике мы будем использовать примеры моделей блога, представленные в руководстве по запросам к базе данных.
Когда 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,
QuerySetможно нарезать, используя синтаксис срезов Python. Нарезание неоценённогоQuerySetобычно возвращает другой неоценённыйQuerySet, но Django выполнит запрос к базе данных, если вы используете параметр "шаг" в синтаксисе среза, и вернёт список. Нарезание уже оценённогоQuerySetтакже возвращает список.Также обратите внимание, что, хотя нарезание неоценённого
QuerySetвозвращает другой неоценённыйQuerySet, дальнейшее изменение (например, добавление дополнительных фильтров или изменение сортировки) не допускается, поскольку это плохо переводится в SQL и не будет иметь ясного смысла. - Сериализация/Кэширование. Подробности о том, что происходит при сериализации QuerySets, см. в следующем разделе. Важно для целей этого раздела, что результаты считываются из базы данных.
-
repr().
QuerySetоценивается при вызовеrepr(). Это сделано для удобства в интерактивном интерпретаторе Python, чтобы вы могли сразу увидеть результаты при интерактивном использовании API. -
len().
QuerySetоценивается при вызовеlen(). Это, как можно ожидать, возвращает длину списка результатов.Примечание: Если вам нужно только определить количество записей в наборе (а не сами объекты), гораздо эффективнее обработать подсчёт на уровне базы данных с помощью SQL
SELECT COUNT(*). Django предоставляет методcount()именно для этой цели. -
list(). Принудительно оцените
QuerySet, вызвавlist(). Например:entry_list = list(Entry.objects.all())
-
bool(). Проверка
QuerySetв булевом контексте, таком как использованиеbool(),or,andили оператораif, приведёт к выполнению запроса. Если существует хотя бы один результат, тоQuerySetявляетсяTrue, в противном случаеFalse. Например:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")Примечание: Если вам нужно только определить, существует ли хотя бы один результат (и вам не нужны сами объекты), более эффективно использовать
exists().
Сериализация QuerySet
Если вы pickle QuerySet, это принудительно загрузит все результаты в память перед сериализацией. Сериализация обычно используется как предварительный этап к кэшированию, и при повторной загрузке кэшированного QuerySet вы хотите, чтобы результаты уже были присутствовали и готовы к использованию (чтение из базы данных может занять некоторое время, что сведёт на нет цель кэширования). Это означает, что при разсериализации QuerySet он содержит результаты на момент его сериализации, а не результаты, которые в настоящее время находятся в базе данных.
Если вы хотите сериализовать только необходимую информацию для восстановления QuerySet из базы данных в будущем, сериализуйте атрибут query QuerySet. Затем вы можете восстановить исходный QuerySet (без загруженных результатов) используя код, подобный этому:
>>> import pickle >>> query = pickle.loads(s) # Assuming 's' is the pickled string. >>> qs = MyModel.objects.all() >>> qs.query = query # Restore the original 'query'.
Атрибут query — это непрозрачный объект. Он представляет собой внутреннее содержимое построения запроса и не является частью публичного API. Тем не менее, безопасно (и полностью поддерживается) сериализовать и десериализовать содержимое атрибута, как описано здесь.
Ограничения на QuerySet.values_list()
Если вы восстанавливаете QuerySet.values_list() с помощью сериализованного атрибута query, он будет преобразован в QuerySet.values():
>>> import pickle
>>> qs = Blog.objects.values_list("id", "name")
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
QuerySet API
Вот формальное объявление QuerySet:
-
class QuerySet(model=None, query=None, using=None, hints=None)[source] -
Обычно при взаимодействии с
QuerySetвы будете использовать его, цепляя фильтры. Для этого большинство методовQuerySetвозвращают новые запросы. Эти методы подробно рассматриваются далее в этом разделе.Класс
QuerySetимеет следующие публичные атрибуты, которые вы можете использовать для интроспекции:-
ordered[source] -
True, еслиQuerySetупорядочен — т.е. имеет условноеorder_by()или порядок по умолчанию в модели.Falseв противном случае.
-
db[source] -
База данных, которая будет использоваться, если запрос будет выполнен сейчас.
Примечание
Параметр
queryдляQuerySetсуществует для того, чтобы специализированные подклассы запросов могли восстановить внутреннее состояние запроса. Значение параметра представляет собой неявное представление этого состояния запроса и не является частью публичного API. -
Методы, возвращающие новые QuerySet
Django предоставляет ряд методов уточнения QuerySet, которые изменяют либо типы результатов, возвращаемых QuerySet, либо способ выполнения SQL-запроса.
Примечание
Эти методы не выполняют запросы к базе данных, поэтому они безопасны для использования в асинхронном коде и не имеют отдельных асинхронных версий.
filter()
-
filter(*args, **kwargs)
Возвращает новый QuerySet, содержащий объекты, соответствующие заданным параметрам поиска.
Параметры поиска (**kwargs) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются через AND в подлежащем SQL-запросе.
Если вам нужны более сложные запросы (например, запросы с OR операторами), вы можете использовать Q objects (*args).
exclude()
-
exclude(*args, **kwargs)
Возвращает новый QuerySet, содержащий объекты, которые не соответствуют заданным параметрам поиска.
Параметры поиска (**kwargs) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются через AND в подлежащем SQL-запросе, а все это заключено в NOT().
В этом примере исключаются все записи, у которых pub_date позже 2005-1-3 И у которых headline равно “Hello”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline="Hello")
В терминах SQL это эквивалентно:
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
В этом примере исключаются все записи, у которых pub_date позже 2005-1-3 ИЛИ заголовок равен “Hello”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline="Hello")
В терминах SQL это эквивалентно:
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
Обратите внимание, что второй пример более ограничен.
Если вам нужны более сложные запросы (например, запросы с OR операторами), вы можете использовать Q objects (*args).
annotate()
-
annotate(*args, **kwargs)
Аннотирует каждый объект в QuerySet с помощью предоставленного списка выражений запроса. Выражение может быть простым значением, ссылкой на поле в модели (или любой связанной модели) или агрегатным выражением (средние значения, суммы и т. д.), вычисленным над объектами, связанными с объектами в QuerySet.
Каждый аргумент annotate() представляет собой аннотацию, которая будет добавлена к каждому объекту в возвращаемом QuerySet.
Функции агрегирования, предоставляемые Django, описаны в Функции агрегирования ниже.
Аннотации, указанные с помощью именованных аргументов, будут использовать имя аргумента в качестве псевдонима аннотации. Анонимные аргументы будут иметь псевдоним, сгенерированный на основе имени функции агрегирования и поля модели, которое агрегируется. Только агрегатные выражения, ссылающиеся на одно поле, могут быть анонимными аргументами. Все остальное должно быть именованным аргументом.
Например, если вы работаете со списком блогов, вы можете захотеть определить, сколько записей сделано в каждом блоге:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count("entry"))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Модель Blog сама по себе не определяет атрибут entry__count, но с помощью именованного аргумента для указания функции агрегирования вы можете контролировать имя аннотации:
>>> q = Blog.objects.annotate(number_of_entries=Count("entry"))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
Для углубленного обсуждения агрегации см. руководство по теме агрегации.
alias()
-
alias(*args, **kwargs)
То же, что и annotate(), но вместо аннотации объектов в QuerySet сохраняет выражение для последующего использования с другими методами QuerySet. Это полезно, когда сам результат выражения не нужен, но он используется для фильтрации, сортировки или как часть сложного выражения. Отсутствие выбора неиспользуемого значения устраняет избыточную работу в базе данных, что должно привести к лучшей производительности.
Например, если вы хотите найти блоги с более чем 5 записями, но не заинтересованы в точном количестве записей, вы можете сделать это так:
>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count("entry")).filter(entries__gt=5)
alias() можно использовать в сочетании с annotate(), exclude(), filter(), order_by() и update(). Для использования алиасированного выражения с другими методами (например, aggregate()) его необходимо преобразовать в аннотацию:
Blog.objects.alias(entries=Count("entry")).annotate(
entries=F("entries"),
).aggregate(Sum("entries"))
filter() и order_by() могут принимать выражения напрямую, но построение и использование выражения часто происходит не в одном месте (например, метод QuerySet создает выражения для последующего использования в представлениях). alias() позволяет наращивать сложные выражения по частям, возможно, на нескольких методах и модулях, ссылаясь на части выражения по их псевдонимам и использовать annotate() для конечного результата.
order_by()
-
order_by(*fields)
По умолчанию, результаты, возвращаемые QuerySet, упорядочиваются по кортежу сортировки, заданному опцией ordering в модели Meta. Вы можете переопределить это для каждого QuerySet, используя метод order_by.
Пример:
Entry.objects.filter(pub_date__year=2005).order_by("-pub_date", "headline")
Результат выше будет упорядочен по pub_date по убыванию, а затем по headline по возрастанию. Минус перед "-pub_date" указывает на убывание. Возрастание подразумевается.
Для случайной сортировки используйте "?", как в примере:
Entry.objects.order_by("?")
Примечание: Запросы с order_by('?') могут быть дорогостоящими и медленными, в зависимости от используемого бэкенда базы данных.
Чтобы отсортировать по полю в другой модели, используйте ту же синтаксис, что и при запросе через отношения моделей. То есть, имя поля, затем два нижних подчеркивания (__), а затем имя поля в новой модели, и так далее для всех моделей, которые требуется объединить. Например:
Entry.objects.order_by("blog__name", "headline")
Если вы пытаетесь отсортировать по полю, которое является отношением к другой модели, Django будет использовать стандартную сортировку связанной модели или сортировку по первичному ключу связанной модели, если не задана опция Meta.ordering. Например, поскольку в модели Blog не указана стандартная сортировка:
Entry.objects.order_by("blog")
…эквивалентно:
Entry.objects.order_by("blog__id")
Если у Blog была опция ordering = ['name'], тогда первый запрос был бы идентичен:
Entry.objects.order_by("blog__name")
Вы также можете сортировать по выражениям запроса, вызвав asc() или desc() для выражения:
Entry.objects.order_by(Coalesce("summary", "headline").desc())
asc() и desc() имеют аргументы (nulls_first и nulls_last), которые управляют тем, как сортируются значения NULL.
Будьте осторожны, сортируя по полям связанных моделей, если вы также используете 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(), включаются в SQL-столбцы SELECT. Это иногда приводит к неожиданным результатам при совместном использовании с 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() использует любое стандартное упорядочивание связанной модели, которое было определено. Возможно, вам придётся явно упорядочить по связи _id или связанному полю, чтобы убедиться, что выражения DISTINCT ON совпадают с теми, что в начале фрагмента ORDER BY. Например, если модель Blog определила ordering по name:
Entry.objects.order_by("blog").distinct("blog")
…это не сработает, потому что запрос будет отсортирован по blog__name, что не соответствует выражению DISTINCT ON. Вам нужно будет явно упорядочить по полю связи _id (blog_id в данном случае) или по связанному (blog__pk), чтобы убедиться, что оба выражения совпадают.
values()
-
values(*fields, **expressions)
Возвращает итератор, который возвращает словари, а не экземпляры моделей, когда используется как итерируемый объект.
Каждый из этих словарей представляет собой объект, ключи которого соответствуют именам атрибутов объектов модели.
В этом примере сравниваются словари values() с обычными объектами модели:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Метод values() принимает необязательные позиционные аргументы, *fields, которые указывают имена полей, до которых должен быть ограничен SELECT. Если вы указываете поля, каждый словарь будет содержать только ключи/значения полей, которые вы указали. Если вы не указываете поля, каждый словарь будет содержать ключ и значение для каждого поля в таблице базы данных.
Пример:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Метод values() также принимает необязательные именованные аргументы, **expressions, которые передаются в annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
Вы можете использовать встроенные и пользовательские запросы в сортировке. Например:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>
Агрегация в рамках условия values() применяется до других аргументов в том же условии values(). Если вам нужно сгруппировать по другому значению, добавьте его в предыдущее условие values().
>>> from django.db.models import Count
>>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
Несколько нюансов, на которые стоит обратить внимание:
-
Если у вас есть поле, названное
foo, которое являетсяForeignKey, вызовvalues()по умолчанию вернёт ключ словаря, названныйfoo_id, так как это имя скрытого атрибута модели, хранящего фактическое значение (атрибутfooссылается на связанную модель). Когда вы вызываетеvalues()и передаёте имена полей, вы можете передать либоfoo, либоfoo_id, и получите то же самое (ключ словаря будет совпадать с именем поля, которое вы передали).Например:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values("blog") <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values("blog_id") <QuerySet [{'blog_id': 1}, ...]> - При использовании
values()вместе сdistinct(), имейте в виду, что сортировка может повлиять на результаты. См. примечание вdistinct()для подробностей. - Если вы используете условие
values()после вызоваextra(), любые поля, определённые аргументомselectв вызовеextra(), должны быть явно включены в вызовvalues(). Любой вызовextra(), сделанный после вызоваvalues(), проигнорирует дополнительные выбранные поля. - Вызов
only()иdefer()послеvalues()не имеет смысла, поэтому это приведёт к ошибкеTypeError. -
Сочетание преобразований и агрегаций требует использования двух вызовов
annotate(), явно или в качестве именованных аргументов вызоваvalues(). Как и выше, если преобразование зарегистрировано для соответствующего типа поля, первый вызовannotate()можно опустить, поэтому следующие примеры эквивалентны:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values("entry__authors__name__lower").annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values(entry__authors__name__lower=Lower("entry__authors__name")).annotate( ... entries=Count("entry") ... ) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate(entry__authors__name__lower=Lower("entry__authors__name")).values( ... "entry__authors__name__lower" ... ).annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
Это полезно, когда вам нужны значения только из небольшого числа доступных полей, и вам не нужна функциональность объекта модели. Более эффективно выбрать только необходимые поля.
Наконец, обратите внимание, что вы можете вызвать filter(), order_by() и т. д. после вызова values(), что означает, что эти два вызова идентичны:
Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()
Авторы Django предпочитают ставить все методы, влияющие на SQL, в первую очередь, за которыми (необязательно) следуют методы, влияющие на вывод (например, values()), но это не имеет принципиального значения. Используйте эту возможность для проявления индивидуальности.
Вы также можете ссылаться на поля связанных моделей с обратными отношениями через атрибуты OneToOneField, ForeignKey и ManyToManyField:
>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Предупреждение
Поскольку атрибуты ManyToManyField и обратные отношения могут иметь несколько связанных строк, включение их может привести к увеличению размера вашего набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в свой запрос values(), в таком случае будут возвращены все возможные комбинации.
Специальные значения для JSONField в SQLite
Из-за того, как реализованы функции JSON_EXTRACT и JSON_TYPE SQL в SQLite, и отсутствия типа данных BOOLEAN, values() вернёт True, False и None вместо "true", "false" и "null" строк для преобразований ключей JSONField.
Условие SELECT, сгенерированное при использовании values(), было обновлено, чтобы учитывать порядок указанных *fields и **expressions.
values_list()
-
values_list(*fields, flat=False, named=False)
Это похоже на values(), но вместо возврата словарей оно возвращает кортежи при итерации. Каждый кортеж содержит значение из соответствующего поля или выражения, переданного в вызов values_list() — поэтому первый элемент — первое поле и т. д. Например:
>>> Entry.objects.values_list("id", "headline")
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list("id", Lower("headline"))
<QuerySet [(1, 'first entry'), ...]>
Если вы передаёте только одно поле, вы также можете передать параметр flat. Если True, это означает, что возвращаемые результаты являются одиночными значениями, а не кортежами из одного элемента. Пример должен прояснить разницу:
>>> Entry.objects.values_list("id").order_by("id")
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list("id", flat=True).order_by("id")
<QuerySet [1, 2, 3, ...]>
Передача flat при наличии более одного поля является ошибкой.
Вы можете передать named=True, чтобы получить результаты в виде namedtuple():
>>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
Использование именованного кортежа может сделать использование результатов более удобочитаемым, за счёт небольшого снижения производительности при преобразовании результатов в именованный кортеж.
Если вы не передаёте никаких значений в values_list(), оно вернёт все поля модели в порядке их объявления.
Частая потребность — получить конкретное значение поля определённого экземпляра модели. Для этого используйте values_list(), за которым следует вызов get():
>>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'
values() и values_list() предназначены в качестве оптимизаций для конкретного случая использования: извлечение подмножества данных без накладных расходов на создание экземпляра модели. Эта аналогия рушится при работе со множественными множественными и другими многозначными отношениями (такими как отношение «один ко многим» обратного внешнего ключа), потому что предположение «одна строка — один объект» не выполняется.
Например, обратите внимание на поведение при запросе через ManyToManyField:
>>> Author.objects.values_list("name", "entry__headline")
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
Авторы с несколькими записями появляются несколько раз, а авторы без записей имеют None для заголовка записи.
Аналогично, при запросе обратного внешнего ключа, None появляется для записей, не имеющих автора:
>>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
Специальные значения для JSONField в SQLite
Из-за того, как реализованы функции JSON_EXTRACT и JSON_TYPE SQL в SQLite, и отсутствия типа данных BOOLEAN, values_list() вернёт True, False и None вместо "true", "false" и "null" строк для преобразований ключей JSONField.
Условие SELECT, сгенерированное при использовании values_list(), было обновлено, чтобы учитывать порядок указанных *fields.
dates()
-
dates(field, kind, order='ASC')
Возвращает объект, который вычисляет список datetime.date объектов, представляющих все доступные даты определенного типа в содержимом QuerySet.
field должен быть именем поля DateField вашей модели. kind должно быть либо "year", либо "month", либо "week", либо "day". Каждый datetime.date объект в списке результатов «обрезан» до заданного type.
-
"year"возвращает список всех уникальных значений года для поля. -
"month"возвращает список всех уникальных значений год/месяц для поля. -
"week"возвращает список всех уникальных значений год/неделя для поля. Все даты будут понедельниками. -
"day"возвращает список всех уникальных значений год/месяц/день для поля.
order, который по умолчанию равен 'ASC', должен быть либо 'ASC', либо 'DESC'. Это определяет порядок сортировки результатов.
Примеры:
>>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]
datetimes()
-
datetimes(field_name, kind, order='ASC', tzinfo=None)
Возвращает объект, который вычисляет список datetime.datetime объектов, представляющих все доступные даты определенного типа в содержимом QuerySet.
field_name должен быть именем поля DateTimeField вашей модели.
kind должно быть либо "year", либо "month", либо "week", либо "day", либо "hour", либо "minute", либо "second". Каждый datetime.datetime объект в списке результатов «обрезан» до заданного type.
order, который по умолчанию равен 'ASC', должен быть либо 'ASC', либо 'DESC'. Это определяет порядок сортировки результатов.
tzinfo определяет часовой пояс, в который преобразуются даты и время до обрезки. Действительно, определенное значение даты и времени имеет разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo. Если он равен None, Django использует текущий часовой пояс. Он не влияет, когда USE_TZ имеет значение False.
Примечание
Эта функция выполняет преобразования часовых поясов непосредственно в базе данных. Вследствие этого ваша база данных должна уметь интерпретировать значение tzinfo.tzname(None). Это приводит к следующим требованиям:
- SQLite: никаких требований. Преобразования выполняются в Python.
- PostgreSQL: никаких требований (см. Часовые пояса).
- Oracle: никаких требований (см. Выбор файла часового пояса).
- MySQL: загрузить таблицы часовых поясов с помощью mysql_tzinfo_to_sql.
none()
-
none()
Вызов none() создаст набор запросов, который никогда не возвращает какие-либо объекты, и запрос не будет выполнен при обращении к результатам. Набор запросов qs.none() является экземпляром EmptyQuerySet.
Примеры:
>>> Entry.objects.none() <QuerySet []> >>> from django.db.models.query import EmptyQuerySet >>> isinstance(Entry.objects.none(), EmptyQuerySet) True
all()
-
all()
Возвращает копию текущего QuerySet (или подкласса QuerySet). Это может быть полезно в ситуациях, когда вы хотите передать либо менеджер модели, либо QuerySet и выполнить дополнительную фильтрацию по результату. После вызова all() на любом объекте у вас обязательно будет QuerySet для работы.
Когда набор запросов QuerySet оценивается, он обычно кэширует свои результаты. Если данные в базе данных могли измениться с момента оценки QuerySet, вы можете получить обновленные результаты для того же запроса, вызвав all() для ранее оцененного QuerySet.
union()
-
union(*other_qs, all=False)
Использует оператор SQL UNION для объединения результатов двух или более наборов запросов QuerySet. Например:
>>> qs1.union(qs2, qs3)
Оператор UNION по умолчанию выбирает только уникальные значения. Чтобы разрешить дубликаты, используйте аргумент all=True.
union(), intersection() и difference() возвращают экземпляры моделей того же типа, что и первый QuerySet, даже если аргументы являются QuerySet других моделей. Передача разных моделей работает, пока список SELECT одинаков во всех QuerySet (по крайней мере, типы, имена не важны, пока типы в том же порядке). В таких случаях вам необходимо использовать имена столбцов из первого QuerySet в методах QuerySet, применяемых к полученному QuerySet. Например:
>>> qs1 = Author.objects.values_list("name")
>>> qs2 = Entry.objects.values_list("headline")
>>> qs1.union(qs2).order_by("name")
Кроме того, только LIMIT, OFFSET, COUNT(*), ORDER BY и указание столбцов (т.е. срезы, count(), exists(), order_by() и values()/values_list()) разрешены для полученного набора запросов QuerySet. Кроме того, базы данных накладывают ограничения на то, какие операции разрешены в объединенных запросах. Например, большинство баз данных не допускают LIMIT или OFFSET в объединенных запросах.
intersection()
-
intersection(*other_qs)
Использует оператор SQL INTERSECT для возврата общих элементов двух или более наборов запросов QuerySet. Например:
>>> qs1.intersection(qs2, qs3)
См. union() для некоторых ограничений.
difference()
-
difference(*other_qs)
Использует оператор SQL EXCEPT для сохранения только элементов, присутствующих в QuerySet, но не в других наборах запросов QuerySet. Например:
>>> qs1.difference(qs2, qs3)
См. union() для некоторых ограничений.
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 наборов запросов, позволив удалить 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, если это необходимо. Основной недостаток заключается в том, что если вы ссылаетесь на какой-либо псевдоним таблицы набора запросов в сыром SQL, Django может изменить этот псевдоним (например, когда набор запросов используется в качестве подзапроса в другом запросе).
Предупреждение
Будьте очень осторожны, когда используете extra(). Каждый раз, когда вы его используете, вы должны экранировать любые параметры, которые может контролировать пользователь, используя params, чтобы защититься от атак SQL-инъекции.
Вы также не должны заключать в кавычки плейсхолдеры в строке SQL. Этот пример уязвим для SQL-инъекции из-за кавычек вокруг %s:
SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
Вы можете узнать больше о том, как работает защита от SQL-инъекций в Django, в разделе Защита от SQL-инъекций.
По определению, эти дополнительные запросы могут быть непереносимы на разные движки баз данных (потому что вы явно пишете SQL-код) и нарушают принцип DRY, поэтому следует избегать их, если это возможно.
Укажите один или несколько из params, select, where или tables. Ни один из аргументов не является обязательным, но вы должны использовать хотя бы один из них.
-
selectАргумент
selectпозволяет добавить дополнительные поля в клаузуSELECT. Он должен быть словарем, сопоставляющим имена атрибутов с SQL-фрагментами для вычисления этих атрибутов.Пример:
Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})В результате каждый объект
Entryбудет иметь дополнительный атрибутis_recent— булево значение, показывающее, больше ли дата в полеpub_date, чем 1 января 2006 года.Django вставляет указанный SQL-фрагмент непосредственно в оператор
SELECT, поэтому результирующий SQL в приведенном выше примере будет чем-то вроде:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Следующий пример более сложный; он выполняет подзапрос, чтобы добавить каждому результату
Blogобъект атрибутentry_count— целочисленное значение, равное количеству связанных объектовEntry:Blog.objects.extra( select={ "entry_count": "SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id" }, )В этом конкретном случае мы используем тот факт, что запрос уже содержит таблицу
blog_blogв своей клаузеFROM.Результирующий SQL в приведенном выше примере будет:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Обратите внимание, что скобки, необходимые большинству СУБД вокруг подзапросов, не требуются в клаузах
selectDjango.В некоторых редких случаях вам может потребоваться передать параметры в SQL-фрагменты в
extra(select=...). Для этой цели используйте параметрselect_params.Это будет работать, например:
Blog.objects.extra( select={"a": "%s", "b": "%s"}, select_params=("one", "two"), )Если вам нужно использовать буквальное значение
%sвнутри вашей строки select, используйте последовательность%%s. -
where/tablesВы можете определить явные SQL-клаузы
WHERE— возможно, для выполнения неявных соединений — с помощьюwhere. Вы можете вручную добавлять таблицы в клаузу SQLFROM, используяtables.whereиtablesоба принимают список строк. Все параметрыwhere"И" с любыми другими критериями поиска.Пример:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
…примерно переводится в следующий SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Будьте осторожны при использовании параметра
tables, если вы указываете таблицы, которые уже используются в запросе. Когда вы добавляете дополнительные таблицы через параметрtables, Django предполагает, что вы хотите включить эту таблицу еще раз, если она уже включена. Это создает проблему, так как имя таблицы затем получит псевдоним. Если таблица появляется несколько раз в операторе SQL, вторая и последующие вхождения должны использовать псевдонимы, чтобы база данных могла их различать. Если вы ссылаетесь на дополнительную таблицу, добавленную в параметр extrawhere, это вызовет ошибки.Обычно вы будете добавлять только дополнительные таблицы, которые еще не появляются в запросе. Однако, если возникнет описанная выше ситуация, есть несколько решений. Во-первых, проверьте, можете ли вы обойтись без включения дополнительной таблицы и использовать уже имеющуюся в запросе. Если это невозможно, поместите свой вызов
extra()в начало построения набора запросов, чтобы ваша таблица была первым использованием этой таблицы. И наконец, если все остальное не поможет, посмотрите на сгенерированный запрос и перепишите добавлениеwhere, используя псевдоним, предоставленный вашей дополнительной таблице. Псевдоним будет одинаковым каждый раз, когда вы строите набор запросов таким же способом, поэтому вы можете полагаться на имя псевдонима, чтобы оно не изменилось. -
order_byЕсли вам нужно отсортировать результирующий набор запросов, используя некоторые из новых полей или таблиц, которые вы включили с помощью
extra(), используйте параметрorder_by, чтобыextra()и передайте последовательность строк. Эти строки должны быть либо полями модели (как в обычном методеorder_by()для наборов запросов), либо в форматеtable_name.column_name, либо псевдонимом для столбца, который вы указали в параметреselectк методуextra().Например:
q = Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"}) q = q.extra(order_by=["-is_recent"])Это отсортирует все элементы, для которых
is_recentравно true, в начале набора результатов (Trueсортируется передFalseв порядке убывания).Это показывает, что вы можете выполнить несколько вызовов
extra(), и он будет вести себя как ожидается (каждый раз добавляя новые ограничения). -
paramsВ параметре
where, описанном выше, можно использовать стандартные плейсхолдеры для строк базы данных Python —'%s', чтобы указать параметры, которые движок базы данных должен автоматически привести к кавычкам. Аргументparams— это список любых дополнительных параметров для подстановки.Пример:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Всегда используйте
paramsвместо непосредственного встраивания значений вwhere, потому чтоparamsгарантирует правильную обработку кавычек в соответствии с вашим конкретным бэкендом. Например, кавычки будут корректно экранированы.Плохо:
Entry.objects.extra(where=["headline='Lennon'"])
Хорошо:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Предупреждение
Если вы выполняете запросы в MySQL, обратите внимание, что неявное приведение типов в MySQL может привести к непредсказуемым результатам при смешивании типов. Если вы запрашиваете столбец строкового типа, но с целочисленным значением, MySQL приведёт типы всех значений в таблице к целочисленному типу перед выполнением сравнения. Например, если ваша таблица содержит значения 'abc', 'def', и вы запрашиваете WHERE mycolumn=0, обе строки будут соответствовать. Чтобы предотвратить это, выполните правильное приведение типов перед использованием значения в запросе.
defer()
-
defer(*fields)
В некоторых сложных ситуациях моделирования данных, ваши модели могут содержать множество полей, некоторые из которых могут содержать много данных (например, текстовые поля), или требовать дорогостоящей обработки для преобразования в объекты Python. Если вы используете результаты набора запросов в ситуации, где вы не знаете, нужны ли вам эти поля, когда вы изначально получаете данные, вы можете сказать 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 attribute документацию), содержащую только поля, которые вы обычно загружаете и используете, где вы иначе могли бы вызвать defer(). Это делает ваш код более понятным для читателя, немного быстрее и потребляет немного меньше памяти в процессе Python.
Например, обе эти модели используют одну и ту же базу данных:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = "app_largetable"
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = "app_largetable"
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer("f2")
Если многие поля нужно дублировать в неуправляемой модели, лучше всего создать абстрактную модель с общими полями, а затем сделать неуправляемую и управляемую модели дочерними по отношению к абстрактной модели.
only()
-
only(*fields)
Метод only() по существу является противоположностью defer(). Только поля, переданные в этот метод и которые не уже указаны как отложенные, загружаются немедленно при оценке набора запросов.
Если у вас есть модель, где почти все поля необходимо отложить, использование only() для указания дополнительного набора полей может привести к более простому коду.
Предположим, у вас есть модель с полями name, age и biography. Следующие два набора запросов идентичны с точки зрения отложенных полей:
Person.objects.defer("age", "biography")
Person.objects.only("name")
Всякий раз, когда вы вызываете only(), заменяется набор полей, которые необходимо загрузить немедленно. Название метода является мнемоническим: только эти поля загружаются немедленно; остальные откладываются. Таким образом, последовательные вызовы only() приводят к тому, что только конечные поля рассматриваются:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
Поскольку defer() действует поэтапно (добавляя поля в отложенный список), вы можете объединить вызовы only() и defer() и всё будет работать логично:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline immediately.
Entry.objects.defer("body").only("headline", "body")
Все предостережения в примечании к документации для defer() также относятся к only(). Используйте его осторожно и только после исчерпания других вариантов.
Использование only() и пропуск поля, запрошенного с помощью select_related(), также является ошибкой. С другой стороны, вызов only() без аргументов вернёт все поля (включая аннотации), извлечённые запросом.
Как и с defer(), вы не можете получить доступ к не загруженным полям из асинхронного кода и ожидать их загрузки. Вместо этого вы получите исключение SynchronousOnlyOperation. Убедитесь, что все поля, к которым вы можете получить доступ, находятся в вашем вызове 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)
Возвращает набор запросов, который заблокирует строки до конца транзакции, генерируя оператор 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:
...
Когда набор запросов оценивается (for entry in entries в данном случае), все сопоставленные записи будут заблокированы до конца блока транзакции, что означает, что другие транзакции будут предотвращены от изменения или получения блокировок на них.
Обычно, если другая транзакция уже получила блокировку на одной из выбранных строк, запрос будет блокироваться до тех пор, пока блокировка не будет освобождена. Если это не то поведение, которое вам нужно, вызовите select_for_update(nowait=True). Это сделает вызов неблокирующим. Если конфликтная блокировка уже получена другой транзакцией, DatabaseError будет поднято при оценке набора запросов. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True) вместо этого. nowait и skip_locked взаимоисключают друг друга, и попытка вызвать select_for_update() с обоими включёнными опциями приведёт к ValueError.
По умолчанию, select_for_update() блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанных в select_related(), блокируются помимо строк модели набора запросов. Если это нежелательно, укажите связанные объекты, которые нужно заблокировать, в select_for_update(of=(...)), используя ту же синтаксис полей, что и в select_related(). Используйте значение 'self' для ссылки на модель набора запросов.
Блокировка родительских моделей в select_for_update(of=(...))
Если вы хотите заблокировать родительские модели при использовании наследования с несколькими таблицами, вы должны указать поля родительской ссылки (по умолчанию <parent_model_name>_ptr) в аргументе of. Например:
Restaurant.objects.select_for_update(of=("self", "place_ptr"))
Использование select_for_update(of=(...)) с указанными полями
Если вы хотите заблокировать модели и указать выбранные поля, например, используя values(), вы должны выбрать по крайней мере одно поле из каждой модели в аргументе of. Модели без выбранных полей не будут заблокированы.
Только для PostgreSQL, вы можете передать no_key=True, чтобы получить более слабую блокировку, которая всё ещё позволяет создавать строки, которые просто ссылаются на заблокированные строки (например, через внешний ключ), в то время как блокировка активна. Документация PostgreSQL содержит больше подробностей о режимах блокировки строк.
Вы не можете использовать select_for_update() для отношений с 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(raw_query, params=(), translations=None, using=None)
Принимает необработанный запрос SQL, выполняет его и возвращает объект django.db.models.query.RawQuerySet. Этот объект RawQuerySet можно перебирать, как и обычный набор QuerySet, для получения объектов.
См. Выполнение необработанных запросов SQL для получения дополнительной информации.
Предупреждение
raw() всегда запускает новый запрос и не учитывает предыдущую фильтрацию. Поэтому, его, как правило, следует вызывать из Manager или из нового объекта 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
ИЛИ (|)
Объединяет два набора запросов, используя оператор 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
| не является коммутативным оператором, так как могут быть сгенерированы различные (хотя и эквивалентные) запросы.
Исключающее ИЛИ (^)
Объединяет два набора запросов, используя оператор 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
)
Методы, не возвращающие QuerySet
Следующие QuerySet методы оценивают QuerySet и возвращают что-то кроме QuerySet.
Эти методы не используют кэш (см. Кэширование и QuerySet). Вместо этого они каждый раз обращаются к базе данных.
Поскольку эти методы оценивают 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()
Здесь, при одновременных запросах, могут быть предприняты несколько попыток сохранить Person с одинаковыми параметрами. Чтобы избежать этой гонки за ресурсом, приведенный выше пример можно переписать с использованием get_or_create() следующим образом:
obj, created = Person.objects.get_or_create(
first_name="John",
last_name="Lennon",
defaults={"birthday": date(1940, 10, 9)},
)
Любые ключевые аргументы, переданные get_or_create() — за исключением необязательного, который называется defaults — будут использованы в вызове get(). Если объект найден, get_or_create() возвращает кортеж этого объекта и False.
Предупреждение
Этот метод является атомарным, предполагая, что база данных обеспечивает уникальность ключевых аргументов (см. unique или unique_together). Если поля, используемые в ключевых аргументах, не имеют ограничения уникальности, одновременные вызовы этого метода могут привести к вставке нескольких строк с одинаковыми параметрами.
Вы можете указать более сложные условия для полученного объекта, объединив get_or_create() с filter() и используя Q objects. Например, чтобы получить Роберта или Боба Марли, если любой из них существует, и создать последнего в противном случае:
from django.db.models import Q
obj, created = Person.objects.filter(
Q(first_name="Bob") | Q(first_name="Robert"),
).get_or_create(last_name="Marley", defaults={"first_name": "Bob"})
Если найдено несколько объектов, get_or_create() вызывает MultipleObjectsReturned. Если объект не найден, get_or_create() создаст и сохранит новый объект, вернув кортеж нового объекта и True. Новый объект будет создан примерно по следующему алгоритму:
params = {k: v for k, v in kwargs.items() if "__" not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
Другими словами, начните с любого не-'defaults' ключевого аргумента, который не содержит двойного подчёркивания (что указывает на неточный поиск). Затем добавьте содержимое defaults, перезаписывая ключи при необходимости, и используйте результат в качестве ключевых аргументов для класса модели. Если в defaults есть вызываемые объекты, вычислите их. Как намекалось выше, это упрощение алгоритма, используемого, но оно содержит все существенные детали. Внутренняя реализация имеет несколько дополнительных проверок ошибок и обрабатывает несколько дополнительных граничных случаев; если вы заинтересованы, прочитайте код.
Если у вас есть поле под названием defaults и вы хотите использовать его как точное соответствие в get_or_create(), используйте 'defaults__exact', например:
Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})
Метод get_or_create() имеет аналогичное поведение при обработке ошибок, что и create(), когда вы используете вручную заданные первичные ключи. Если объект нужно создать, а ключ уже существует в базе данных, будет вызвано исключение IntegrityError.
Наконец, несколько слов об использовании get_or_create() в представлениях Django. Пожалуйста, используйте его только в POST запросах, если у вас нет веской причины не делать этого. GET запросы не должны оказывать никакого влияния на данные. Вместо этого используйте POST всякий раз, когда запрос на страницу оказывает побочное действие на ваши данные. Для получения дополнительной информации см. Безопасные методы в спецификации HTTP.
Предупреждение
Вы можете использовать get_or_create() через атрибуты ManyToManyField и обратные связи. В этом случае вы ограничите запросы в рамках этой связи. Это может привести к проблемам целостности, если вы не используете его последовательно.
Предположим следующие модели:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
Вы можете использовать get_or_create() через поле глав книги, но это только запрос в контексте этой книги:
>>> book = Book.objects.create(title="Ulysses") >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, True) >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, False) >>> Chapter.objects.create(title="Chapter 1") <Chapter: Chapter 1> >>> book.chapters.get_or_create(title="Chapter 1") # Raises IntegrityError
Это происходит, потому что он пытается получить или создать «Главу 1» через книгу «Улисс», но не может сделать ни то, ни другое: связь не может получить эту главу, потому что она не связана с этой книгой, но также не может её создать, потому что поле title должно быть уникальным.
update_or_create()
-
update_or_create(defaults=None, create_defaults=None, **kwargs)
-
aupdate_or_create(defaults=None, create_defaults=None, **kwargs)
Асинхронная версия: aupdate_or_create()
Удобный метод для обновления объекта заданными kwargs, создавая новый, если необходимо. Оба 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не будут отправлены. - Он не работает с дочерними моделями в сценарии наследования с несколькими таблицами.
- Если первичный ключ модели —
AutoFieldи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, где значение по умолчанию таково, что используется не более 999 переменных на запрос.
На базах данных, которые его поддерживают (все, кроме Oracle), установка параметра ignore_conflicts в значение True сообщает базе данных игнорировать ошибки вставки строк, которые не удовлетворяют ограничениям, таким как дублирование уникальных значений.
На базах данных, которые его поддерживают (все, кроме Oracle), установка параметра update_conflicts в значение True сообщает базе данных обновить update_fields, когда вставка строки завершается ошибкой из-за конфликтов. В PostgreSQL и SQLite, помимо update_fields, должен быть предоставлен список unique_fields, которые могут быть в конфликте.
Включение параметра ignore_conflicts отключает установку первичного ключа для каждого экземпляра модели (если база данных это обычно поддерживает).
Предупреждение
В MySQL и MariaDB установка параметра ignore_conflicts в значение True преобразует некоторые типы ошибок, помимо ошибки дублирования ключа, в предупреждения. Даже в режиме строгости. Например: недействительные значения или нарушения обязательности. Подробнее см. документацию MySQL здесь и документацию MariaDB здесь.
bulk_update()
-
bulk_update(objs, fields, batch_size=None)
-
abulk_update(objs, fields, batch_size=None)
Асинхронная версия: abulk_update()
Этот метод эффективно обновляет указанные поля для предоставленных экземпляров модели, как правило, с одним запросом, и возвращает количество обновлённых объектов:
>>> objs = [ ... Entry.objects.create(headline="Entry 1"), ... Entry.objects.create(headline="Entry 2"), ... ] >>> objs[0].headline = "This is entry 1" >>> objs[1].headline = "This is entry 2" >>> Entry.objects.bulk_update(objs, ["headline"]) 2
Используется QuerySet.update() для сохранения изменений, поэтому это более эффективно, чем перебор списка моделей и вызов save() для каждого из них, но у него есть некоторые ограничения:
- Вы не можете обновить первичный ключ модели.
- Метод
save()каждой модели не вызывается, и сигналыpre_saveиpost_saveне отправляются. - При обновлении большого количества столбцов в большом количестве строк генерируемый SQL может быть очень большим. Избегайте этого, указав подходящее значение
batch_size. - Обновление полей, определённых в предках наследования с несколькими таблицами, потребует дополнительного запроса на каждый предок.
- Когда отдельные партии содержат дубликаты, только первый экземпляр в этой партии приведёт к обновлению.
- Количество обновлённых объектов, возвращаемое функцией, может быть меньше, чем количество переданных объектов. Это может быть из-за дублированных объектов, переданных в одной партии, или из-за проблем гонки, так что объекты больше не присутствуют в базе данных.
Параметр batch_size управляет тем, сколько объектов сохраняется в одном запросе. Значение по умолчанию — все объекты в одной партии, за исключением SQLite и Oracle, у которых есть ограничения на количество переменных, используемых в запросе.
count()
-
count()
-
acount()
Асинхронная версия: acount()
Возвращает целое число, представляющее количество объектов в базе данных, соответствующих QuerySet.
Пример:
# Returns the total number of entries in the database. Entry.objects.count() # Returns the number of entries whose headline contains 'Lennon' Entry.objects.filter(headline__contains="Lennon").count()
Вызов count() выполняет SELECT COUNT(*) в фоновом режиме, поэтому вы всегда должны использовать count(), а не загружать все записи в объекты Python и вызывать len() на результате (если вам не нужно загружать объекты в память, в этом случае len() будет быстрее).
Обратите внимание, что если вам нужно количество элементов в QuerySet и вы также извлекаете экземпляры модели из него (например, перебирая его), то, вероятно, эффективнее использовать len(queryset), что не вызовет дополнительного запроса к базе данных, в отличие от count().
Если набор запросов уже полностью получен, count() будет использовать его длину, а не выполнять дополнительный запрос к базе данных.
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.
Набор запросов обычно кеширует свои результаты, чтобы повторные оценки не приводили к дополнительным запросам. В отличие от этого, iterator() будет читать результаты напрямую, без кеширования на уровне QuerySet (внутренне, стандартный итератор вызывает iterator() и кеширует возвращаемое значение). Для набора запросов, возвращающего большое количество объектов, которые вам нужно получить только один раз, это может привести к лучшей производительности и значительному сокращению использования памяти.
Обратите внимание, что использование iterator() на наборе запросов, который уже был вычислен, заставит его перевычислиться, повторив запрос.
iterator() совместим с предыдущими вызовами prefetch_related(), при условии, что chunk_size предоставлено. Более крупные значения потребуют меньшего количества запросов для выполнения предварительной выборки за счет увеличения использования памяти.
В некоторых базах данных (например, Oracle, SQLite) может быть ограничено максимальное количество терминов в предложении SQL IN. Следовательно, следует использовать значения, меньшие этого предела. (В частности, при предварительной выборке по двум или более отношениям, chunk_size должно быть достаточно малым, чтобы ожидаемое число результатов для каждого предварительно выбранного отношения все еще находилось ниже предела.)
Пока набор запросов не предварительно выбирает связанные объекты, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявное значение по умолчанию 2000.
В зависимости от базы данных результаты запроса будут загружаться либо все сразу, либо передаваться из базы данных с помощью серверных курсоров.
С серверными курсорами
Oracle и PostgreSQL используют серверные курсоры для потоковой передачи результатов из базы данных без загрузки всего набора результатов в память.
Драйвер Oracle базы данных всегда использует серверные курсоры.
При использовании серверных курсоров параметр chunk_size указывает количество результатов для кеширования на уровне драйвера базы данных. Получение больших блоков уменьшает количество циклов между драйвером базы данных и базой данных за счет увеличения использования памяти.
В PostgreSQL серверные курсоры будут использоваться только тогда, когда настройка DISABLE_SERVER_SIDE_CURSORS имеет значение False. Прочитайте Пулы транзакций и серверные курсоры, если вы используете пул подключений, настроенный в режиме пула транзакций. Когда серверные курсоры отключены, поведение такое же, как в базах данных, которые не поддерживают серверные курсоры.
Без серверных курсоров
MySQL не поддерживает потоковую передачу результатов, поэтому драйвер базы данных Python загружает весь набор результатов в память. Затем адаптер базы данных преобразует набор результатов в объекты строк Python с использованием метода fetchmany(), определенного в PEP 249.
SQLite может получать результаты партиями с помощью fetchmany(), но так как SQLite не обеспечивает изоляцию между запросами в рамках одного подключения, будьте осторожны при записи в таблицу, по которой итерируетесь. См. Изоляция при использовании QuerySet.iterator() для получения дополнительной информации.
Параметр chunk_size управляет размером партий, которые Django получает от драйвера базы данных. Более крупные партии уменьшают издержки взаимодействия с драйвером базы данных за счет небольшого увеличения потребления памяти.
Пока набор запросов не предварительно выбирает связанные объекты, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявное значение по умолчанию 2000, значение, полученное из расчета на списке рассылки psycopg:
Предполагая строки из 10-20 столбцов со смешанными текстовыми и числовыми данными, 2000 будет загружать менее 100 КБ данных, что кажется хорошим компромиссом между количеством передаваемых строк и отбрасываемыми данными, если цикл завершается преждевременно.
latest()
-
latest(*fields)
-
alatest(*fields)
Асинхронная версия: alatest()
Возвращает последний объект в таблице на основе заданного(ых) поля(ей).
Этот пример возвращает последний Entry в таблице в соответствии с полем pub_date:
Entry.objects.latest("pub_date")
Вы также можете выбрать последний на основе нескольких полей. Например, чтобы выбрать Entry с самой ранней expire_date, когда у двух записей одинаковое значение pub_date:
Entry.objects.latest("pub_date", "-expire_date")
Отрицательный знак в '-expire_date' означает сортировку expire_date в понижающем порядке. Так как latest() получает последний результат, выбирается Entry с самой ранней expire_date.
Если в Meta вашей модели указано get_latest_by, вы можете опустить любые аргументы для earliest() или latest(). По умолчанию будут использоваться поля, указанные в get_latest_by.
Как и get(), earliest() и latest() вызывают исключение DoesNotExist, если объект с заданными параметрами отсутствует.
Обратите внимание, что earliest() и latest() существуют исключительно для удобства и удобочитаемости.
earliest() и latest() могут возвращать экземпляры с нулевыми датами.
Поскольку сортировка делегируется базе данных, результаты по полям, допускающим нулевые значения, могут сортироваться по-разному при использовании различных баз данных. Например, PostgreSQL и MySQL сортируют нулевые значения так, как будто они больше, чем ненулевые значения, в то время как SQLite делает наоборот.
Вы можете отфильтровать нулевые значения:
Entry.objects.filter(pub_date__isnull=False).latest("pub_date")
earliest()
-
earliest(*fields)
-
aearliest(*fields)
Асинхронная версия: aearliest()
Работает аналогично latest(), за исключением изменения направления.
first()
-
first()
-
afirst()
Асинхронная версия: afirst()
Возвращает первый объект, соответствующий запросу, или None, если соответствующего объекта нет. Если у QuerySet нет определённой сортировки, то набор запросов автоматически сортируется по первичному ключу. Это может повлиять на результаты агрегации, как описано в Взаимодействии с order_by().
Пример:
p = Article.objects.order_by("title", "pub_date").first()
Обратите внимание, что first() это удобный метод, следующий фрагмент кода эквивалентен приведенному выше примеру:
try:
p = Article.objects.order_by("title", "pub_date")[0]
except IndexError:
p = None
last()
-
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"))
{'entry__count': 16}
Используя именованный аргумент для указания функции агрегации, вы можете контролировать имя возвращаемого значения агрегации:
>>> Blog.objects.aggregate(number_of_entries=Count("entry"))
{'number_of_entries': 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.exists() выполнит больше общей работы (один запрос для проверки существования плюс дополнительный запрос для последующего получения результатов), чем использование bool(some_queryset), которое извлекает результаты, а затем проверяет, были ли возвращены какие-либо результаты.
contains()
-
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().
Наконец, обратите внимание, что 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 может использовать быстрый путь и удалять объекты без загрузки в память. Для больших удалений это может значительно сократить использование памяти. Также можно уменьшить количество выполняемых запросов.
ForeignKeys, которые установлены в on_delete DO_NOTHING, не препятствуют выбору быстрого пути при удалении.
Обратите внимание, что запросы, сгенерированные при удалении объектов, являются деталями реализации и могут быть изменены.
as_manager()
-
classmethod as_manager()
Метод класса, который возвращает экземпляр Manager с копией методов QuerySet. Подробнее см. Создание менеджера с методами QuerySet.
Обратите внимание, что в отличие от других элементов этого раздела, у него нет асинхронного варианта, так как он не выполняет запрос.
explain()
-
explain(format=None, **options)
-
aexplain(format=None, **options)
Асинхронная версия: aexplain()
Возвращает строку с планом выполнения QuerySet, в которой подробно описывается, как база данных выполнит запрос, включая используемые индексы или соединения. Знание этих деталей может помочь вам улучшить производительность медленных запросов.
Например, при использовании PostgreSQL:
>>> print(Blog.objects.filter(title="My Blog").explain()) Seq Scan on blog (cost=0.00..35.50 rows=10 width=12) Filter: (title = 'My Blog'::bpchar)
Вывод значительно отличается между базами данных.
explain() поддерживается во всех встроенных базах данных, кроме Oracle, так как реализация там нетривиальна.
Параметр format изменяет формат вывода по умолчанию баз данных, который обычно текстовый. PostgreSQL поддерживает форматы 'TEXT', 'JSON', 'YAML' и 'XML'. MariaDB и MySQL поддерживают форматы 'TEXT' (также называемый 'TRADITIONAL') и 'JSON'. MySQL 8.0.16+ также поддерживает улучшенный формат 'TREE', который аналогичен выводу 'TEXT' PostgreSQL и используется по умолчанию, если поддерживается.
Некоторые базы данных принимают флаги, которые могут вернуть больше информации о запросе. Передайте эти флаги в качестве аргументов ключевых слов. Например, при использовании PostgreSQL:
>>> print(Blog.objects.filter(title="My Blog").explain(verbose=True, analyze=True)) Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1) Output: id, title Filter: (blog.title = 'My Blog'::bpchar) Planning time: 0.064 ms Execution time: 0.058 ms
В некоторых базах данных флаги могут привести к выполнению запроса, что может оказать негативное влияние на вашу базу данных. Например, флаг ANALYZE, поддерживаемый MariaDB, MySQL 8.0.18+ и PostgreSQL, может привести к изменениям данных, если есть триггеры или вызывается функция, даже для запроса SELECT.
Добавлена поддержка опции generic_plan для PostgreSQL 16+.
Добавлена поддержка опций memory и serialize для PostgreSQL 17+.
Field запросы
Запросы к полям позволяют указать суть условия SQL-WHERE. Они задаются в качестве именованных аргументов для методов QuerySet filter(), exclude() и get().
Для ознакомления см. документацию по моделям и запросам к базе данных.
Встроенные запросы Django перечислены ниже. Также можно написать собственные запросы для полей модели.
Для удобства, когда тип запроса не указан (например, в Entry.objects.get(id=14)), тип запроса предполагается exact.
exact
Точное совпадение. Если предоставленное значение для сравнения — None, оно будет интерпретировано как SQL-NULL (см. isnull для получения дополнительной информации).
Примеры:
Entry.objects.get(id__exact=14) Entry.objects.get(id__exact=None)
Эквиваленты SQL:
SELECT ... WHERE id = 14; SELECT ... WHERE id IS NULL;
Сравнения MySQL
В MySQL настройка «кодировки» таблицы базы данных определяет, являются ли сравнения exact регистрозависимыми. Это настройка базы данных, а не Django. Можно настроить таблицы MySQL для регистрозависимых сравнений, но это влечет за собой некоторые компромиссы. Подробнее об этом см. раздел кодировки в документации по базам данных.
iexact
Регистронезависимое точное совпадение. Если предоставленное значение для сравнения — None, оно будет интерпретировано как SQL-NULL (см. isnull для получения дополнительной информации).
Пример:
Blog.objects.get(name__iexact="beatles blog") Blog.objects.get(name__iexact=None)
Эквиваленты SQL:
SELECT ... WHERE name ILIKE 'beatles blog'; SELECT ... WHERE name IS NULL;
Обратите внимание, что первый запрос найдет 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG' и т. д.
Пользователи SQLite
При использовании бэкенда SQLite и строк, не являющихся ASCII, помните примечание к базе данных о сравнении строк. SQLite не выполняет регистронезависимое сопоставление для строк, не являющихся ASCII.
contains
Регистрозависимое проверка вхождения.
Пример:
Entry.objects.get(headline__contains="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline LIKE '%Lennon%';
Обратите внимание, что это найдет заголовок 'Lennon honored today', но не 'lennon
honored today'.
Пользователи SQLite
SQLite не поддерживает регистрозависимые операторы LIKE; contains работает как icontains в SQLite. Дополнительную информацию см. в примечании к базе данных.
icontains
Регистронезависимое проверка вхождения.
Пример:
Entry.objects.get(headline__icontains="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline ILIKE '%Lennon%';
Пользователи SQLite
При использовании бэкенда SQLite и строк, не являющихся ASCII, помните примечание к базе данных о сравнении строк.
in
В заданном итерируемом объекте; часто списке, кортеже или наборе запросов. Это нечастый случай использования, но принимаются и строки (так как они итерируемы).
Примеры:
Entry.objects.filter(id__in=[1, 3, 4]) Entry.objects.filter(headline__in="abc")
Эквиваленты SQL:
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
Вы также можете использовать набор запросов для динамической оценки списка значений вместо предоставления списка литеральных значений:
inner_qs = Blog.objects.filter(name__contains="Cheddar") entries = Entry.objects.filter(blog__in=inner_qs)
Этот набор запросов будет оцениваться как подзапрос:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Если вы передаете QuerySet, полученный из values() или values_list(), в качестве значения для запроса __in, вам необходимо убедиться, что из результата извлекается только одно поле. Например, это сработает (фильтрация по именам блогов):
inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Этот пример вызовет исключение, так как внутренний запрос пытается извлечь два значения полей, а ожидается только одно:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Соображения по производительности
Будьте осторожны при использовании вложенных запросов и понимайте характеристики производительности вашего сервера базы данных (в случае сомнений, проведите бенчмаркинг!). Некоторые бэкэнды баз данных, особенно MySQL, не очень хорошо оптимизируют вложенные запросы. В таких случаях эффективнее извлечь список значений и затем передать его во второй запрос. То есть, выполните два запроса вместо одного:
values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Обратите внимание на list() вызов вокруг блога QuerySet, чтобы принудительно выполнить первый запрос. Без него будет выполнен вложенный запрос, так как наборы запросов ленивые.
gt
Больше чем.
Пример:
Entry.objects.filter(id__gt=4)
Эквивалент SQL:
SELECT ... WHERE id > 4;
gte
Больше или равно.
lt
Меньше чем.
lte
Меньше или равно.
startswith
Регистрозависимое начинается с.
Пример:
Entry.objects.filter(headline__startswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite не поддерживает регистрозависимые операторы LIKE; startswith работает как istartswith в SQLite.
istartswith
Регистронезависимое начинается с.
Пример:
Entry.objects.filter(headline__istartswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline ILIKE 'Lennon%';
Пользователи SQLite
При использовании бэкенда SQLite и строк, не являющихся ASCII, помните примечание к базе данных о сравнении строк.
endswith
Регистрозависимое заканчивается на.
Пример:
Entry.objects.filter(headline__endswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline LIKE '%Lennon';
Пользователи SQLite
SQLite не поддерживает регистрозависимые операторы LIKE; endswith работает как iendswith в SQLite. Смотрите документацию примечания к базе данных для получения более подробной информации.
iendswith
Регистронезависимое заканчивается на.
Пример:
Entry.objects.filter(headline__iendswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline ILIKE '%Lennon'
Пользователи SQLite
При использовании бэкенда SQLite и строк, не являющихся ASCII, помните примечание к базе данных о сравнении строк.
range
Проверка диапазона (включая границы).
Пример:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
Эквивалент SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Вы можете использовать range везде, где вы можете использовать BETWEEN в SQL — для дат, чисел и даже символов.
Предупреждение
Фильтрация DateTimeField с датами не будет включать элементы в последний день, потому что границы интерпретируются как «0:00 в указанную дату». Если pub_date была DateTimeField, вышеприведенное выражение было бы преобразовано в следующий SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Как правило, нельзя смешивать даты и datetime.
date
Для полей datetime преобразует значение в дату. Разрешает цепочку дополнительных запросов к полям. Принимает значение даты.
Пример:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(Для этого запроса нет эквивалентного фрагмента SQL-кода, так как реализация соответствующего запроса варьируется в разных базах данных.)
Если USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
year
Для полей date и datetime точное совпадение года. Позволяет цепочку дополнительных запросов к полям. Принимает целое число — год.
Пример:
Entry.objects.filter(pub_date__year=2005) Entry.objects.filter(pub_date__year__gte=2005)
Эквивалент SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31'; SELECT ... WHERE pub_date >= '2005-01-01';
(Точный синтаксис SQL варьируется для каждого движка базы данных.)
Если USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
iso_year
Для полей даты и времени, точное совпадение года по ISO 8601. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое число года.
Пример:
Entry.objects.filter(pub_date__iso_year=2005) Entry.objects.filter(pub_date__iso_year__gte=2005)
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
month
Для полей даты и времени, точное совпадение месяца. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое число от 1 (январь) до 12 (декабрь).
Пример:
Entry.objects.filter(pub_date__month=12) Entry.objects.filter(pub_date__month__gte=6)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
day
Для полей даты и времени, точное совпадение дня. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое число дня.
Пример:
Entry.objects.filter(pub_date__day=3) Entry.objects.filter(pub_date__day__gte=3)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date на третий день месяца, например, 3 января, 3 июля и т. д.
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
week
Для полей даты и времени возвращает номер недели (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
Для полей даты и времени совпадение по «дню недели». Разрешает цепочку дополнительных поисковых запросов по полям.
Принимает целое значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).
Пример:
Entry.objects.filter(pub_date__week_day=2) Entry.objects.filter(pub_date__week_day__gte=2)
(Для этого поиска не включён эквивалентный фрагмент кода SQL, поскольку реализация соответствующего запроса варьируется в разных базах данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date, которая выпадает на понедельник (день 2 недели), независимо от месяца или года, в котором это происходит. Дни недели индексируются с днем 1, являющимся воскресеньем, и днем 7, являющимся субботой.
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
iso_week_day
Для полей даты и времени точное совпадение дня недели по ISO 8601. Разрешает цепочку дополнительных поисковых запросов по полям.
Принимает целое значение, представляющее день недели от 1 (понедельник) до 7 (воскресенье).
Пример:
Entry.objects.filter(pub_date__iso_week_day=1) Entry.objects.filter(pub_date__iso_week_day__gte=1)
(Для этого поиска не включён эквивалентный фрагмент кода SQL, поскольку реализация соответствующего запроса варьируется в разных базах данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date, которая выпадает на понедельник (день 1 недели), независимо от месяца или года, в котором это происходит. Дни недели индексируются с днем 1, являющимся понедельником, и днем 7, являющимся воскресеньем.
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
quarter
Для полей даты и времени совпадение «четверти года». Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое значение от 1 до 4, представляющее четверть года.
Пример для получения записей во второй четверти (с 1 апреля по 30 июня):
Entry.objects.filter(pub_date__quarter=2)
(Для этого поиска не включён эквивалентный фрагмент кода SQL, поскольку реализация соответствующего запроса варьируется в разных базах данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
time
Для полей datetime приведение значения к типу времени. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает значение datetime.time.
Пример:
Entry.objects.filter(pub_date__time=datetime.time(14, 30)) Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(Для этого поиска не включён эквивалентный фрагмент кода SQL, поскольку реализация соответствующего запроса варьируется в разных базах данных.)
Когда USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
hour
Для полей datetime и time, точное совпадение часа. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое число от 0 до 23.
Пример:
Event.objects.filter(timestamp__hour=23) Event.objects.filter(time__hour=5) Event.objects.filter(timestamp__hour__gte=12)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
minute
Для полей datetime и time, точное совпадение минуты. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__minute=29) Event.objects.filter(time__minute=46) Event.objects.filter(timestamp__minute__gte=29)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
second
Для полей datetime и time, точное совпадение секунды. Разрешает цепочку дополнительных поисковых запросов по полям. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__second=31) Event.objects.filter(time__second=2) Event.objects.filter(timestamp__second__gte=31)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых поясов в базе данных.
isnull
Принимает либо True, либо False, что соответствует SQL-запросам IS NULL и IS NOT NULL соответственно.
Пример:
Entry.objects.filter(pub_date__isnull=True)
SQL-эквивалент:
SELECT ... WHERE pub_date IS NULL;
regex
Совпадение с регулярным выражением, учитывающим регистр.
Синтаксис регулярных выражений соответствует используемому обратному движку базы данных. В случае SQLite, который не имеет встроенной поддержки регулярных выражений, эта функция предоставляется пользовательской функцией REGEXP (на Python), и поэтому синтаксис регулярных выражений соответствует синтаксису модуля re Python.
Пример:
Entry.objects.get(title__regex=r"^(An?|The) +")
SQL-эквиваленты:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Использование сырых строк (например, r'foo' вместо 'foo') для передачи синтаксиса регулярного выражения рекомендуется.
iregex
Совпадение с регулярным выражением, не учитывающим регистр.
Пример:
Entry.objects.get(title__iregex=r"^(an?|the) +")
SQL-эквиваленты:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Функции агрегирования
Django предоставляет следующие функции агрегирования в модуле django.db.models. Подробную информацию о том, как использовать эти агрегатные функции, см. в руководстве по агрегированию. Ознакомьтесь с документацией Aggregate, чтобы узнать, как создавать свои агрегаты.
Предупреждение
SQLite не может обрабатывать агрегирование по полям даты/времени «из коробки». Это связано с тем, что в SQLite нет встроенных полей даты/времени, и Django в настоящее время эмулирует эти возможности с помощью текстового поля. Попытки использовать агрегирование по полям даты/времени в SQLite приведут к ошибке NotSupportedError.
Пустые наборы запросов или группы
Функции агрегирования возвращают значение None при использовании с пустым набором QuerySet или группой. Например, функция агрегирования Sum возвращает значение None вместо 0, если набор QuerySet не содержит записей или для любой пустой группы в непустом наборе QuerySet. Чтобы вернуть другое значение, определите аргумент default. Count является исключением из этого правила; она возвращает 0, если набор QuerySet пуст, так как Count не поддерживает аргумент default.
Все агрегаты имеют следующие общие параметры:
expressions
Строки, которые ссылаются на поля модели, преобразования поля или выражения запроса.
output_field
Необязательный аргумент, представляющий поле модели возвращаемого значения
Примечание
При комбинировании нескольких типов полей Django может определить только output_field, если все поля имеют один и тот же тип. В противном случае вы должны указать output_field самостоятельно.
filter
Необязательный Q object, который используется для фильтрации строк, которые агрегируются.
См. Условное агрегирование и Фильтрация аннотаций для примеров использования.
default
Необязательный аргумент, позволяющий указать значение по умолчанию, которое будет использоваться, когда набор запросов (или группировка) не содержит записей.
**extra
Ключевые аргументы, которые могут предоставить дополнительный контекст для SQL-запроса, сгенерированного агрегатом.
Avg
-
class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[source] -
Возвращает среднее значение заданного выражения, которое должно быть числовым, если вы не укажете другое
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)[source] -
Возвращает количество объектов, связанных через предоставленное выражение.
Count('*')эквивалентно SQL-выражениюCOUNT(*).- Значение по умолчанию:
<field>__count - Тип возвращаемого значения:
int
-
distinct -
Необязательно. Если
distinct=True, подсчёт будет включать только уникальные экземпляры. Это SQL-эквивалентCOUNT(DISTINCT <field>). Значение по умолчанию:False.
Примечание
Аргумент
defaultне поддерживается. - Значение по умолчанию:
Max
-
class Max(expression, output_field=None, filter=None, default=None, **extra)[source] -
Возвращает максимальное значение заданного выражения.
- Значение по умолчанию:
<field>__max - Тип возвращаемого значения: такой же, как поле ввода, или
output_field, если указан. Если набор запросов или группировка пустая, возвращаетсяdefault.
- Значение по умолчанию:
Min
-
class Min(expression, output_field=None, filter=None, default=None, **extra)[source] -
Возвращает минимальное значение заданного выражения.
- Значение по умолчанию:
<field>__min - Тип возвращаемого значения: такой же, как поле ввода, или
output_field, если указан. Если набор запросов или группировка пустая, возвращаетсяdefault.
- Значение по умолчанию:
StdDev
-
class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)[source] -
Возвращает стандартное отклонение данных в предоставленном выражении.
- Значение по умолчанию:
<field>__stddev - Тип возвращаемого значения:
float, если входной параметрint, иначе такой же, как поле ввода, илиoutput_field, если указан. Если набор запросов или группировка пустая, возвращаетсяdefault.
-
sample -
Необязательно. По умолчанию
StdDevвозвращает стандартное отклонение генеральной совокупности. Однако, еслиsample=True, возвращаемое значение будет выборочным стандартным отклонением.
- Значение по умолчанию:
Sum
-
class Sum(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[source] -
Вычисляет сумму всех значений заданного выражения.
- Значение по умолчанию:
<field>__sum - Тип возвращаемого значения: такой же, как поле ввода, или
output_field, если указан. Если набор запросов или группировка пустая, возвращаетсяdefault.
-
distinct -
Необязательно. Если
distinct=True,Sumвозвращает сумму уникальных значений. Это SQL-эквивалентSUM(DISTINCT <field>). Значение по умолчанию:False.
- Значение по умолчанию:
Variance
-
class Variance(expression, output_field=None, sample=False, filter=None, default=None, **extra)[source] -
Возвращает дисперсию данных в предоставленном выражении.
- Значение по умолчанию:
<field>__variance - Тип возвращаемого значения:
float, если входной параметрint, иначе такой же, как поле ввода, илиoutput_field, если указан. Если набор запросов или группировка пустая, возвращаетсяdefault.
-
sample -
Необязательно. По умолчанию
Varianceвозвращает дисперсию генеральной совокупности. Однако, еслиsample=True, возвращаемое значение будет выборочной дисперсией.
- Значение по умолчанию:
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/ref/models/querysets/