Справочник по API QuerySet
В этом документе подробно описан API QuerySet. Он основан на материалах, представленных в руководствах по моделям и запросам к базе данных, поэтому, вероятно, перед чтением этого документа вам стоит ознакомиться с ними.
В этом справочнике мы будем использовать примеры моделей блога, представленные в руководстве по запросам к базе данных.
Когда вычисляются QuerySetы
Внутри QuerySet можно создавать, фильтровать, срезать и в целом передавать дальше, не обращаясь при этом к базе данных. Работа с базой данных начинается только тогда, когда вы выполняете действие, вычисляющее набор запросов.
Вычислить QuerySet можно следующими способами:
-
Итерация. По
QuerySetможно выполнять итерацию; запрос к базе данных выполняется при первой итерации. Например, этот код выведет заголовки всех записей в базе данных:for e in Entry.objects.all(): print(e.headline)Примечание. Не используйте этот способ, если вам нужно лишь определить, существует ли хотя бы один результат. Эффективнее воспользоваться методом
exists(). -
Асинхронная итерация. По
QuerySetтакже можно выполнять итерацию с помощьюasync for:async for e in Entry.objects.all(): results.append(e)Синхронные и асинхронные итераторы QuerySet используют общий кэш.
-
Срезы. Как объясняется в разделе Ограничение QuerySet, для
QuerySetможно использовать синтаксис срезов массивов Python. Срез невычисленногоQuerySetобычно возвращает другой невычисленныйQuerySet, однако Django выполнит запрос к базе данных и вернёт список, если вы используете параметр «шаг» в синтаксисе среза. Срез уже вычисленногоQuerySetтакже возвращает список.Обратите также внимание: хотя срез невычисленного
QuerySetвозвращает другой невычисленныйQuerySet, дальнейшее его изменение (например, добавление фильтров или изменение порядка сортировки) запрещено, поскольку это нельзя корректно преобразовать в SQL, и такое изменение не имело бы ясного смысла. - Сериализация/кэширование. Подробнее о том, что происходит при сериализации QuerySet, см. в следующем разделе. Для целей этого раздела важно, что результаты считываются из базы данных.
-
repr().
QuerySetвычисляется при вызове для негоrepr(). Это сделано для удобства работы в интерактивном интерпретаторе Python: при интерактивном использовании API результаты отображаются сразу. -
len().
QuerySetвычисляется при вызове для негоlen(). Как и следовало ожидать, эта функция возвращает длину списка результатов.Примечание. Если вам нужно только определить количество записей в наборе (а сами объекты не нужны), гораздо эффективнее выполнить подсчёт на уровне базы данных с помощью SQL-оператора
SELECT COUNT(*). Именно для этого Django предоставляет методcount(). -
list(). Принудительно вычислить
QuerySetможно, вызвав для негоlist(). Например:entry_list = list(Entry.objects.all())
-
bool(). Проверка
QuerySetв булевом контексте, например с помощьюbool(),or,andили инструкцииif, приведёт к выполнению запроса. Если есть хотя бы один результат,QuerySetимеет значениеTrue, в противном случае —False. Например:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")Примечание. Если вам нужно лишь определить, существует ли хотя бы один результат (а сами объекты не нужны), эффективнее воспользоваться методом
exists().
Сериализация QuerySetов
Если вы pickle объект QuerySet, все результаты будут загружены в память до сериализации. Сериализация обычно используется перед кэшированием; когда кэшированный набор запросов загружается повторно, результаты должны быть уже доступны и готовы к использованию (чтение из базы данных может занять некоторое время и свести на нет пользу кэширования). Это означает, что после десериализации QuerySet содержит результаты на момент сериализации, а не актуальные на данный момент результаты из базы данных.
Если вы хотите сериализовать только сведения, необходимые для повторного создания QuerySet из базы данных позднее, сериализуйте атрибут 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)[исходный код] -
Обычно при работе с
QuerySetвы будете использовать его, объединяя фильтры в цепочку. Чтобы это работало, большинство методовQuerySetвозвращают новые наборы запросов. Эти методы подробно описаны далее в этом разделе.Класс
QuerySetимеет следующие общедоступные атрибуты, которые можно использовать для интроспекции:-
ordered[исходный код] -
True, еслиQuerySetупорядочен, то есть содержит предложениеorder_by()или модель имеет порядок сортировки по умолчанию. В противном случае —False.
-
db[исходный код] -
База данных, которая будет использоваться, если этот запрос будет выполнен сейчас.
Примечание
Параметр
queryклассаQuerySetсуществует для того, чтобы специализированные подклассы запросов могли восстанавливать внутреннее состояние запроса. Значение параметра — непрозрачное представление этого состояния; оно не является частью публичного API. -
Методы, возвращающие новые наборы QuerySet
Django предоставляет ряд методов уточнения QuerySet, которые изменяют тип результатов, возвращаемых QuerySet, или способ выполнения его SQL-запроса.
Примечание
Эти методы не выполняют запросы к базе данных, поэтому их безопасно вызывать в асинхронном коде; отдельных асинхронных версий у них нет.
filter()
-
filter(*args, **kwargs)
Возвращает новый QuerySet, содержащий объекты, соответствующие заданным параметрам поиска.
Параметры поиска (**kwargs) должны иметь формат, описанный ниже в разделе Поиск по полям. Несколько параметров объединяются с помощью AND в базовом SQL-выражении.
Для выполнения более сложных запросов (например, запросов с выражениями OR) можно использовать Q objects (*args).
exclude()
-
exclude(*args, **kwargs)
Возвращает новый QuerySet, содержащий объекты, не соответствующие заданным параметрам поиска.
Параметры поиска (**kwargs) должны иметь формат, описанный ниже в разделе Поиск по полям. Несколько параметров объединяются с помощью AND в базовом SQL-выражении, а всё выражение заключается в NOT().
В этом примере исключаются все записи, у которых pub_date позже 2005-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 аннотации из переданного списка выражений запроса или объектов Q. Каждому объекту можно добавить аннотацию в виде:
- простого значения с помощью
Value(); - ссылки на поле модели (или любой связанной модели) с помощью
F(); - логического значения с помощью
Q(); или - результата агрегатного выражения (среднее, сумма и т. д.), вычисленного для объектов, связанных с объектами в
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, в SQL-запросе которого используется SELECT DISTINCT. Это удаляет из результатов запроса повторяющиеся строки.
По умолчанию QuerySet не удаляет повторяющиеся строки. На практике это редко становится проблемой, поскольку простые запросы, такие как Blog.objects.all(), не могут возвращать повторяющиеся строки. Однако при запросе, охватывающем несколько таблиц, при вычислении QuerySet могут появиться повторяющиеся результаты. В этом случае следует использовать distinct().
Примечание
Все поля, используемые при вызове order_by(), включаются в столбцы SELECT SQL-запроса. Иногда это приводит к неожиданным результатам при использовании вместе с distinct(). Если сортировать по полям связанной модели, эти поля будут добавлены в выбираемые столбцы и могут привести к тому, что строки, которые иначе считались бы повторяющимися, будут признаны уникальными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они нужны только для сортировки), иногда кажется, что возвращаются неуникальные результаты.
Аналогично, если для ограничения выбираемых столбцов используется запрос values(), столбцы, используемые в любом вызове order_by() (или в сортировке модели по умолчанию), всё равно будут учитываться и могут повлиять на уникальность результатов.
Вывод: при использовании distinct() будьте осторожны с сортировкой по связанным моделям. Аналогично, при совместном использовании distinct() и values() будьте осторожны, сортируя по полям, не указанным в вызове values().
Только в PostgreSQL можно передать позиционные аргументы (*fields), чтобы указать имена полей, к которым следует применить DISTINCT. В результате формируется SQL-запрос SELECT DISTINCT ON. Вот в чём разница. При обычном вызове distinct() база данных при определении уникальности сравнивает каждое поле в каждой строке. При вызове distinct() с указанными именами полей база данных сравнивает только эти поля.
Примечание
При указании имён полей вы обязаны задать order_by() в QuerySet, причём поля в order_by() должны начинаться с полей из distinct() в том же порядке.
Например, SELECT DISTINCT ON (a) возвращает первую строку для каждого значения столбца a. Если не задать порядок сортировки, будет возвращена произвольная строка.
Примеры (все примеры, кроме первого, работают только в PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by("pub_date").distinct("pub_date")
[...]
>>> Entry.objects.order_by("blog").distinct("blog")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
[...]
>>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author")
[...]
Примечание
Помните, что order_by() учитывает заданный порядок сортировки по умолчанию связанной модели. Возможно, потребуется явно указать сортировку по связи _id или по связанному полю, чтобы выражения DISTINCT ON совпадали с полями в начале предложения ORDER BY. Например, если для модели Blog задан параметр ordering со значением name:
Entry.objects.order_by("blog").distinct("blog")
…не сработает, поскольку запрос будет отсортирован по blog__name, что не соответствует выражению DISTINCT ON. Чтобы оба выражения совпадали, необходимо явно указать сортировку по полю связи _id (в данном случае blog_id) или по связанному полю (blog__pk).
values()
-
values(*fields, **expressions)
Возвращает QuerySet, который при переборе возвращает словари, а не экземпляры моделей.
Каждый такой словарь представляет объект; его ключи соответствуют именам атрибутов объектов модели.
В этом примере сравниваются словари values() с обычными объектами модели:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Метод values() принимает необязательные позиционные аргументы *fields, задающие поля, которыми следует ограничить SELECT. Если указать поля, каждый словарь будет содержать только ключи и значения этих полей. Если поля не указаны, каждый словарь будет содержать ключ и значение для каждого поля таблицы базы данных.
Пример:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Метод values() также принимает необязательные именованные аргументы **expressions, которые передаются в annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
Для сортировки можно использовать встроенные и пользовательские способы поиска. Например:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>
Агрегация внутри предложения values() выполняется до обработки остальных аргументов того же предложения values(). Если нужно группировать по другому значению, добавьте его в предыдущее предложение values(). Например:
>>> from django.db.models import Count
>>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
Стоит упомянуть несколько нюансов:
-
Если у вас есть поле
foo, являющеесяForeignKey, вызовvalues()по умолчанию вернёт ключ словаря с именемfoo_id, поскольку это имя скрытого атрибута модели, в котором хранится фактическое значение (атрибутfooссылается на связанную модель). При вызовеvalues()с передачей имён полей можно указать какfoo, так иfoo_id— результат будет одинаковым (ключ словаря будет соответствовать переданному имени поля).Например:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values("blog") <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values("blog_id") <QuerySet [{'blog_id': 1}, ...]> - При совместном использовании
values()иdistinct()учитывайте, что сортировка может повлиять на результаты. Подробности см. в примечании кdistinct(). - Если после вызова
extra()использовать предложениеvalues(), поля, заданные аргументом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}]>
Этот метод полезен, если вам нужны значения только нескольких доступных полей и функциональность объекта экземпляра модели не требуется. Выбирать только нужные поля эффективнее.
Наконец, обратите внимание: после вызова values() можно вызывать filter(), order_by() и т. д.; следовательно, эти два вызова эквивалентны:
Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()
Создатели Django предпочитают сначала указывать все методы, влияющие на SQL, а затем (при необходимости) методы, влияющие на вывод (например, values()), но это не имеет особого значения. Это ваш шанс в полной мере проявить индивидуальность.
Также можно обращаться к полям связанных моделей с обратными связями через атрибуты OneToOneField, ForeignKey и ManyToManyField:
>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Предупреждение
Поскольку атрибуты ManyToManyField и обратные связи могут соответствовать нескольким связанным строкам, их включение может значительно увеличить размер результирующего набора. Эффект особенно заметен, если в запрос values() включено несколько таких полей: в этом случае будут возвращены все возможные комбинации.
Специальные значения для JSONField в SQLite
Из-за особенностей реализации функций SQL JSON_EXTRACT и JSON_TYPE в SQLite и отсутствия типа данных BOOLEAN для преобразований ключей JSONField values() возвращает True, False и None вместо строк "true", "false" и "null".
Предложение 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
Из-за особенностей реализации SQL-функций JSON_EXTRACT и JSON_TYPE в SQLite, а также отсутствия типа данных BOOLEAN, для преобразований ключей JSONField метод values_list() возвращает True, False и None вместо строк "true", "false" и "null".
Оператор SELECT, генерируемый при использовании values_list(), был обновлён: теперь он учитывает порядок указанных *fields.
dates()
-
dates(field, kind, order='ASC')
Возвращает QuerySet, который при вычислении даёт список объектов datetime.date, представляющих все имеющиеся даты определённого типа в содержимом QuerySet.
field должно быть именем DateField вашей модели. Значением kind должно быть "year", "month", "week" или "day". Каждый объект datetime.date в результирующем списке «усекается» до указанного type.
-
"year"возвращает список всех уникальных значений года для этого поля. -
"month"возвращает список всех уникальных сочетаний года и месяца для этого поля. -
"week"возвращает список всех уникальных сочетаний года и недели для этого поля. Все даты будут приходиться на понедельник. -
"day"возвращает список всех уникальных сочетаний года, месяца и дня для этого поля.
order, по умолчанию равный 'ASC', должен быть 'ASC' или 'DESC'. Он определяет порядок сортировки результатов.
Примеры:
>>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]
datetimes()
-
datetimes(field_name, kind, order='ASC', tzinfo=None)
Возвращает QuerySet, который при вычислении даёт список объектов datetime.datetime, представляющих все имеющиеся даты определённого типа в содержимом QuerySet.
field_name должно быть именем DateTimeField вашей модели.
Значением kind должно быть "year", "month", "week", "day", "hour", "minute" или "second". Каждый объект datetime.datetime в результирующем списке «усекается» до указанного type.
order, по умолчанию равный 'ASC', должен быть 'ASC' или 'DESC'. Он определяет порядок сортировки результатов.
Параметр tzinfo задаёт часовой пояс, в который преобразуются значения даты и времени перед усечением. Одно и то же значение даты и времени может иметь разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo. Если он равен None, Django использует текущий часовой пояс. Параметр не влияет на результат, если USE_TZ равен False.
Примечание
Эта функция выполняет преобразование часовых поясов непосредственно в базе данных. Поэтому база данных должна уметь интерпретировать значение tzinfo.tzname(None). Это накладывает следующие требования:
- SQLite: требований нет. Преобразования выполняются в Python.
- PostgreSQL: требований нет (см. раздел Часовые пояса).
- Oracle: требований нет (см. раздел Выбор файла часовых поясов).
- MySQL: загрузите таблицы часовых поясов с помощью mysql_tzinfo_to_sql.
none()
-
none()
Вызов none() создаёт queryset, который никогда не возвращает объекты; при обращении к результатам запрос не выполняется. qs.none() queryset — это экземпляр 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")
Кроме того, для результирующего QuerySet разрешены только LIMIT, OFFSET, COUNT(*), ORDER BY и указание столбцов (то есть срезы, count(), exists(), order_by() и values()/values_list()). Кроме того, базы данных накладывают ограничения на операции, разрешённые для объединённых запросов. Например, большинство баз данных не разрешают 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. Если вам всё же необходимо его использовать, пожалуйста, создайте тикет с ключевым словом QuerySet.extra, описав свой сценарий использования (сначала проверьте список уже существующих тикетов), чтобы мы могли расширить API QuerySet и отказаться от extra(). Мы больше не улучшаем этот метод и не исправляем в нём ошибки.
Например, это использование extra():
>>> qs.extra(
... select={"val": "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
эквивалентно:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
Главное преимущество использования RawSQL заключается в том, что при необходимости можно задать output_field. Главный недостаток состоит в том, что если в необработанном SQL-коде вы ссылаетесь на псевдоним таблицы из queryset, Django может изменить этот псевдоним (например, если queryset используется как подзапрос в другом запросе).
Предупреждение
Используйте extra() с большой осторожностью. Каждый раз, когда вы используете этот метод, необходимо экранировать все параметры, которыми может управлять пользователь, с помощью params, чтобы защититься от SQL-инъекций.
Кроме того, в SQL-строке нельзя заключать заполнители в кавычки. Этот пример уязвим для SQL-инъекции из-за кавычек вокруг %s:
SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
Подробнее о работе защиты 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_date1 января 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"), )Если в строке select нужно использовать буквальный символ
%s, укажите последовательность%%s. -
where/tablesС помощью
whereможно задавать явные предложения SQLWHERE, например для выполнения неявных соединений. Вручную добавить таблицы в предложение SQLFROMможно с помощьюtables.Аргументы
whereиtablesпринимают список строк. Все параметрыwhereобъединяются оператором «AND» с другими критериями поиска.Пример:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
…примерно соответствует следующему SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Будьте осторожны с параметром
tables, если указываете таблицы, уже используемые в запросе. Добавляя дополнительные таблицы с помощью параметраtables, Django предполагает, что вы хотите включить эту таблицу ещё раз, если она уже присутствует. Это создаёт проблему, поскольку таблице будет присвоен псевдоним. Если таблица встречается в SQL-операторе несколько раз, для второго и последующих вхождений необходимо использовать псевдонимы, чтобы СУБД могла различать их. Если вы ссылаетесь на дополнительную таблицу, добавленную через параметрwhere, это приведёт к ошибкам.Обычно в запрос добавляют только дополнительные таблицы, которых в нём ещё нет. Однако если возникла описанная выше ситуация, есть несколько решений. Сначала проверьте, можно ли обойтись без дополнительной таблицы и использовать уже присутствующую в запросе. Если это невозможно, поместите вызов
extra()в начало построения queryset, чтобы ваша таблица использовалась первой. Наконец, если ничего не помогает, изучите сформированный запрос и перепишите добавлениеwhere, используя псевдоним, присвоенный дополнительной таблице. При одинаковом построении queryset псевдоним будет каждый раз одним и тем же, поэтому на его имя можно полагаться. -
order_byЕсли нужно упорядочить результирующий queryset по новым полям или таблицам, добавленным с помощью
extra(), передайте в параметрorder_byметодаextra()последовательность строк. Эти строки должны представлять собой либо поля модели (как и в обычном методе querysetorder_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. Если вы используете результаты queryset в ситуации, когда при первоначальной загрузке данных неизвестно, понадобятся ли вам эти поля, можно указать Django не получать их из базы данных.
Для этого передайте в defer() имена полей, которые не нужно загружать:
Entry.objects.defer("headline", "body")
Queryset с отложенными полями по-прежнему возвращает экземпляры модели. Каждое отложенное поле будет загружено из базы данных при обращении к нему (по одному, а не все отложенные поля сразу).
Примечание
В асинхронном коде отложенные поля не будут загружаться таким образом по требованию. Вместо этого будет вызвано исключение SynchronousOnlyOperation. Если вы пишете асинхронный код, не пытайтесь обращаться к полям, которые вы defer().
Можно вызывать defer() несколько раз. Каждый вызов добавляет новые поля в набор отложенных:
# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")
Порядок добавления полей в набор отложенных не имеет значения. Вызов defer() с именем поля, которое уже было отложено, безопасен (поле останется отложенным).
Можно отложить загрузку полей связанных моделей (если связанные модели загружаются с помощью select_related()), используя стандартную нотацию с двойным подчёркиванием для разделения связанных полей:
Blog.objects.select_related().defer("entry__headline", "entry__body")
Чтобы очистить набор отложенных полей, передайте None в качестве параметра в defer():
# Load all fields immediately. my_queryset.defer(None)
Некоторые поля модели не будут отложены, даже если вы этого попросите. Загрузку первичного ключа отложить нельзя. Если для получения связанных моделей используется select_related(), не следует откладывать загрузку поля, связывающего основную модель со связанной: это приведёт к ошибке.
Аналогично, вызов defer() (или его аналога only()) с аргументом, полученным в результате агрегации (например, с использованием результата annotate()), не имеет смысла и вызовет исключение. Агрегированные значения всегда загружаются в результирующий queryset.
Примечание
Метод defer() (и его аналог only(), описанный ниже) предназначен только для сложных сценариев использования. Он позволяет оптимизировать запросы, если вы тщательно их проанализировали, точно понимаете, какая информация вам нужна, и измерили, что разница между возвратом нужных полей и полного набора полей модели будет существенной.
Даже если вы считаете, что ваш сценарий относится к сложным, используйте defer() только тогда, когда во время загрузки queryset невозможно определить, понадобятся ли вам дополнительные поля. Если вы часто загружаете и используете определённую подгруппу данных, лучше нормализовать модели и поместить незагружаемые данные в отдельную модель (и таблицу базы данных). Если по какой-либо причине столбцы должны оставаться в одной таблице, создайте модель с 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(). При вычислении queryset немедленно загружаются только поля, переданные этому методу и не указанные ранее как отложенные.
Если почти все поля модели нужно отложить, указание дополняющего набора полей с помощью only() может упростить код.
Предположим, у вас есть модель с полями name, age и biography. Следующие два queryset эквивалентны с точки зрения отложенных полей:
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() без аргументов возвращает все поля (включая аннотации), загруженные queryset.
Как и в случае с 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)
Возвращает queryset, который блокирует строки до конца транзакции и генерирует оператор SQL SELECT ... FOR UPDATE в поддерживаемых СУБД.
Например:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
При вычислении queryset (в данном случае for entry in entries) все совпавшие записи будут заблокированы до конца блока транзакции, то есть другие транзакции не смогут изменять их или устанавливать на них блокировки.
Обычно, если другая транзакция уже заблокировала одну из выбранных строк, запрос будет ожидать снятия блокировки. Если такое поведение нежелательно, вызовите select_for_update(nowait=True). Вызов перестанет блокироваться в ожидании. Если другая транзакция уже установила конфликтующую блокировку, при вычислении queryset будет вызвано исключение DatabaseError. Также можно пропустить заблокированные строки с помощью select_for_update(skip_locked=True). Параметры nowait и skip_locked взаимоисключающие; попытка вызвать select_for_update() с обоими включёнными параметрами приведёт к исключению ValueError.
По умолчанию select_for_update() блокирует все строки, выбранные запросом. Например, помимо строк модели queryset блокируются строки связанных объектов, указанных в select_related(). Если это нежелательно, укажите в select_for_update(of=(...)) связанные объекты, которые нужно заблокировать, используя тот же синтаксис полей, что и в select_related(). Чтобы сослаться на модель queryset, используйте значение '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() для nullable-связей:
>>> 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
Чтобы обойти это ограничение, можно исключить объекты со значением null, если они вас не интересуют:
>>> 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. Это предотвращает неожиданное блокирование кода.
Вычисление queryset с 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() обычно завершается ошибкой в режиме autocommit, 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.
Операторы, возвращающие новые QuerySets
Объединяемые queryset должны относиться к одной и той же модели.
AND (&)
Объединяет два QuerySets с помощью 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
OR (|)
Объединяет два QuerySets с помощью 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
| — некоммутативная операция, поскольку могут быть сформированы разные (хотя и эквивалентные) запросы.
XOR (^)
Объединяет два QuerySets с помощью 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))
Если вы ожидаете, что QuerySet уже вернёт одну строку, можно вызвать 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. Например, чтобы получить Robert или Bob Marley, если кто-либо из них существует, а иначе создать последнего:
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() через поле chapters модели Book, но поиск будет ограничен контекстом этой книги:
>>> 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
Это происходит потому, что выполняется попытка получить или создать «Chapter 1» для книги «Ulysses», но ни то ни другое невозможно: связь не может получить эту главу, поскольку она не связана с этой книгой, и не может создать её, поскольку поле 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()
Этот метод эффективно добавляет переданный список объектов в базу данных (обычно выполняя всего один запрос независимо от количества объектов) и возвращает созданные объекты в виде списка в том же порядке, в каком они были переданы:
>>> objs = Entry.objects.bulk_create( ... [ ... Entry(headline="This is a test"), ... Entry(headline="This is only a test"), ... ] ... )
Однако у этого метода есть ряд ограничений:
- Метод
save()модели не будет вызван, а сигналыpre_saveиpost_saveотправлены не будут. - Метод не работает с дочерними моделями при использовании многоуровневого наследования.
- Если первичный ключ модели — это
AutoFieldили имеет значениеdb_default, аignore_conflictsимеет значениеFalse, получить атрибут первичного ключа можно только в некоторых базах данных (в настоящее время PostgreSQL, MariaDB и SQLite 3.35+). В других базах данных он не будет установлен. - Метод не работает со связями «многие ко многим».
-
Метод преобразует
objsв список, полностью вычисляяobjs, если это генератор. Такое преобразование позволяет проверить все объекты и сначала добавить те, у которых первичный ключ задан вручную. Если вы хотите добавлять объекты пакетами, не вычисляя весь генератор сразу, можно использовать следующий приём, если у объектов нет первичных ключей, заданных вручную:from itertools import islice batch_size = 100 objs = (Entry(headline="Test %s" % i) for i in range(1000)) while True: batch = list(islice(objs, batch_size)) if not batch: break Entry.objects.bulk_create(batch, batch_size)
Параметр batch_size задаёт количество объектов, создаваемых за один запрос. По умолчанию все объекты создаются одним пакетом, за исключением SQLite, где значение по умолчанию ограничивает число переменных в запросе до 999.
В поддерживающих эту возможность базах данных (во всех, кроме Oracle) установка параметра ignore_conflicts в True указывает базе данных игнорировать ошибки добавления строк, нарушающих ограничения, например из-за дублирующихся уникальных значений.
В поддерживающих эту возможность базах данных (во всех, кроме Oracle) установка параметра update_conflicts в True указывает базе данных обновить update_fields при конфликте во время добавления строки. В PostgreSQL и SQLite, помимо update_fields, необходимо передать список unique_fields, для которых возможен конфликт.
Включение параметра ignore_conflicts отключает установку первичного ключа для каждого экземпляра модели (если база данных обычно поддерживает такую возможность).
Предупреждение
В MySQL и MariaDB установка параметра ignore_conflicts в True превращает некоторые типы ошибок, не связанные с дублированием ключей, в предупреждения. Это происходит даже в строгом режиме. Например, это относится к недопустимым значениям или нарушениям ограничений NOT NULL. Подробнее см. в документации 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(), не приведёт к дополнительному запросу к базе данных.
Если QuerySet уже полностью получен, 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 для этих значений и возвращает словарь, в котором каждому значению соответствует экземпляр объекта с этим значением поля. Метод in_bulk никогда не вызывает исключения django.core.exceptions.ObjectDoesNotExist: любые значения id_list, не соответствующие ни одному экземпляру, просто игнорируются. Если id_list не указан, возвращаются все объекты QuerySet. field_name должно быть уникальным полем или полем, по которому выполняется выборка уникальных значений (если в distinct() указано только одно поле). По умолчанию field_name равен первичному ключу.
Например:
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(["beatles_blog"], field_name="slug")
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct("name").in_bulk(field_name="name")
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}
Если передать in_bulk() пустой список, будет возвращён пустой словарь.
iterator()
-
iterator(chunk_size=None)
-
aiterator(chunk_size=None)
Асинхронная версия: aiterator()
Вычисляет QuerySet (выполняя запрос) и возвращает итератор (см. PEP 234) для перебора результатов либо асинхронный итератор (см. PEP 492), если вызвать асинхронную версию aiterator.
Обычно QuerySet кэширует результаты, чтобы повторное вычисление не приводило к дополнительным запросам. В отличие от него, iterator() читает результаты напрямую, не кэшируя их на уровне QuerySet (внутри итератор по умолчанию вызывает iterator() и кэширует возвращаемое значение). Для QuerySet, возвращающего большое количество объектов, к которым нужно обратиться только один раз, это может повысить производительность и значительно снизить расход памяти.
Обратите внимание: вызов iterator() для QuerySet, который уже был вычислен, заставит вычислить его повторно и выполнить запрос ещё раз.
iterator() совместим с предыдущими вызовами prefetch_related(), если задан параметр chunk_size. Большие значения позволят сократить число запросов, необходимых для предварительной загрузки, но потребуют больше памяти.
В некоторых базах данных (например, Oracle и SQLite) может быть ограничено максимальное число элементов в предложении SQL IN. Поэтому следует использовать значения, не превышающие этот предел. (В частности, при предварительной загрузке через две или более связи значение chunk_size должно быть достаточно небольшим, чтобы ожидаемое количество результатов для каждой предварительно загружаемой связи не превышало лимит.)
Если QuerySet не выполняет предварительную загрузку связанных объектов, отсутствие значения для 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 от драйвера базы данных. Большие пакеты уменьшают накладные расходы на взаимодействие с драйвером базы данных, но немного увеличивают расход памяти.
Если QuerySet не выполняет предварительную загрузку связанных объектов, отсутствие значения для 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__authors"))
{'entry__authors__count': 16}
Задав агрегатную функцию с помощью именованного аргумента, можно управлять именем возвращаемого агрегированного значения:
>>> Blog.objects.aggregate(number_of_authors=Count("entry__authors"))
{'number_of_authors': 16}
Подробное обсуждение агрегации см. в руководстве по теме «Агрегация».
exists()
-
exists()
-
aexists()
Асинхронная версия: aexists()
Возвращает True, если QuerySet содержит какие-либо результаты, и False в противном случае. Метод пытается выполнить запрос максимально простым и быстрым способом, но при этом фактически выполняет почти тот же запрос, что и обычный запрос QuerySet.
exists() полезен для проверки наличия объектов в QuerySet, особенно в случае большого QuerySet.
Чтобы проверить, содержит ли набор запросов какие-либо элементы:
if some_queryset.exists():
print("There is at least one object in some_queryset")
Это будет быстрее, чем:
if some_queryset:
print("There is at least one object in some_queryset")
… но ненамного (поэтому для повышения эффективности нужен большой набор запросов).
Кроме того, если some_queryset ещё не вычислен, но вы знаете, что это произойдёт позже, использование some_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().
MySQL не поддерживает обновления с предварительной выборкой из той же таблицы
В MySQL при фильтрации по связанным таблицам QuerySet.update() может выполнить SELECT, а затем UPDATE вместо одного UPDATE. Если между запросами происходят параллельные изменения, это может привести к состоянию гонки. Чтобы обеспечить атомарность, рассмотрите возможность использования транзакций или отказа от таких условий фильтрации в MySQL.
Наконец, помните, что update() выполняет обновление на уровне SQL и поэтому не вызывает методы save() моделей и не отправляет сигналы pre_save или post_save (которые отправляются при вызове Model.save()). Если нужно обновить несколько записей модели, у которой переопределён метод save(), переберите их и вызовите save(), например так:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
Упорядоченный набор запросов
Цепочка вызовов order_by() и update() поддерживается только в MariaDB и MySQL и игнорируется другими базами данных. Это полезно для обновления уникального поля в заданном порядке без конфликтов. Например:
Entry.objects.order_by("-number").update(number=F("number") + 1)
Примечание
Предложение order_by() будет проигнорировано, если оно содержит аннотации, унаследованные поля или обращения к полям через связи.
delete()
-
delete()
-
adelete()
Асинхронная версия: adelete()
Выполняет SQL-запрос на удаление всех строк из QuerySet и возвращает количество удалённых объектов и словарь с количеством удалений для каждого типа объектов.
Метод delete() выполняется немедленно. Нельзя вызвать delete() для QuerySet, для которого был получен срез или который по другой причине больше нельзя фильтровать.
Например, чтобы удалить все записи определённого блога:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})
По умолчанию ForeignKey в Django имитирует ограничение SQL ON DELETE CASCADE — другими словами, все объекты, внешние ключи которых указывают на удаляемые объекты, будут удалены вместе с ними. Например:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})
Это каскадное поведение можно настроить с помощью аргумента on_delete у ForeignKey.
Метод delete() выполняет массовое удаление и не вызывает методы delete() моделей. Однако он отправляет сигналы pre_delete и post_delete для всех удалённых объектов, включая объекты, удалённые каскадно.
Django необходимо загружать объекты в память, чтобы отправлять сигналы и обрабатывать каскадное удаление. Однако, если каскадного удаления нет и сигналы не отправляются, Django может использовать быстрый путь и удалять объекты без загрузки в память. При удалении большого количества объектов это может значительно сократить расход памяти. Также может уменьшиться количество выполняемых запросов.
ForeignKey, у которых задано 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.
Добавлена поддержка параметров 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 с учетом регистра; в SQLite contains работает как icontains. Подробнее см. примечание в документации по базе данных.
icontains
Проверка на вхождение без учета регистра.
Пример:
Entry.objects.get(headline__icontains="Lennon")
Эквивалентный запрос SQL:
SELECT ... WHERE headline ILIKE '%Lennon%';
Пользователям SQLite
При использовании SQLite и строк, содержащих символы, отличные от ASCII, учитывайте примечание о сравнении строк в документации по базе данных.
in
В заданном итерируемом объекте, обычно списке, кортеже или QuerySet. Это не самый распространенный сценарий, но строки (поскольку они являются итерируемыми объектами) также принимаются.
Примеры:
Entry.objects.filter(id__in=[1, 3, 4]) Entry.objects.filter(headline__in="abc")
Эквивалентные запросы SQL:
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
Можно также использовать QuerySet для динамического вычисления списка значений вместо передачи списка литеральных значений:
inner_qs = Blog.objects.filter(name__contains="Cheddar") entries = Entry.objects.filter(blog__in=inner_qs)
Этот QuerySet будет выполнен как подзапрос:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Если передать QuerySet, полученный в результате values() или values_list(), в качестве значения для поиска __in, необходимо убедиться, что из результата извлекается только одно поле. Например, следующий вариант будет работать (поиск по названиям блогов):
inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Этот пример вызовет исключение, поскольку внутренний запрос пытается извлечь значения двух полей, хотя ожидается только одно:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Вопросы производительности
Будьте осторожны при использовании вложенных запросов и учитывайте особенности производительности вашего сервера базы данных (если сомневаетесь — проведите тестирование!). Некоторые серверные части баз данных, в частности MySQL, плохо оптимизируют вложенные запросы. В таких случаях эффективнее извлечь список значений, а затем передать его во второй запрос. То есть выполнить два запроса вместо одного:
values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Обратите внимание на вызов list() для Blog QuerySet, который принудительно запускает первый запрос. Без него был бы выполнен вложенный запрос, поскольку 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 с учетом регистра; в SQLite startswith работает как istartswith.
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 с учетом регистра; в SQLite endswith работает как iendswith. Подробнее см. документацию в примечании о базе данных.
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';
В SQL range можно использовать везде, где допустимо BETWEEN, — для дат, чисел и даже символов.
Предупреждение
При фильтрации DateTimeField по датам записи за последний день не попадут в результат, поскольку границы интерпретируются как «полночь в указанную дату». Если бы pub_date был DateTimeField, приведенное выше выражение преобразовалось бы в такой запрос SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Как правило, нельзя смешивать даты и дату со временем.
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
Для полей даты и даты со временем — точное совпадение по году. Позволяет объединять с дополнительными поисками по полям. Принимает целочисленное значение года.
Пример:
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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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 различается для разных движков баз данных.)
Обратите внимание: будут найдены все записи с датой публикации, приходящейся на третье число месяца, например 3 января, 3 июля и т. д.
Если USE_TZ имеет значение True, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
quarter
Для полей даты и даты со временем — совпадение по кварталу года. Позволяет объединять с дополнительными поисками по полям. Принимает целое число от 1 до 4, обозначающее квартал года.
Пример получения записей за второй квартал (с 1 апреля по 30 июня):
Entry.objects.filter(pub_date__quarter=2)
(Эквивалентный фрагмент кода SQL для этого способа поиска не приводится, поскольку реализация соответствующего запроса различается в разных движках баз данных.)
Если USE_TZ имеет значение True, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
time
Для полей даты со временем преобразует значение к типу времени. Позволяет объединять с дополнительными поисками по полям. Принимает значение 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
Для полей даты со временем и времени — точное совпадение по часу. Позволяет объединять с дополнительными поисками по полям. Принимает целое число от 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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
minute
Для полей даты со временем и времени — точное совпадение по минуте. Позволяет объединять с дополнительными поисками по полям. Принимает целое число от 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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
second
Для полей даты со временем и времени — точное совпадение по секунде. Позволяет объединять с дополнительными поисками по полям. Принимает целое число от 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, поля даты со временем перед фильтрацией преобразуются в текущий часовой пояс. Для этого необходимы определения часовых поясов в базе данных.
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, поэтому применяется синтаксис регулярных выражений модуля Python re.
Пример:
Entry.objects.get(title__regex=r"^(An?|The) +")
Эквивалентные запросы SQL:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Для передачи синтаксиса регулярного выражения рекомендуется использовать необработанные строки (например, 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-кода, создаваемого агрегатом.
AnyValue
-
class AnyValue(expression, output_field=None, filter=None, default=None, **extra)[исходный код] -
Возвращает произвольное значение из входных значений, отличных от NULL.
- Псевдоним по умолчанию:
<field>__anyvalue - Тип возвращаемого значения: совпадает с типом входного поля или
output_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
Пример использования:
>>> # Get average rating for each year along with a sample headline >>> # from that year. >>> from django.db.models import AnyValue, Avg, F, Q >>> sample_headline = AnyValue("headline") >>> Entry.objects.values( ... pub_year=F("pub_date__year"), ... ).annotate( ... avg_rating=Avg("rating"), ... sample_headline=sample_headline, ... ) >>> # Get a sample headline from each year with rating greater than 4.5. >>> sample_headline = AnyValue( ... "headline", ... filter=Q(rating__gt=4.5), ... ) >>> Entry.objects.values( ... pub_year=F("pub_date__year"), ... ).annotate( ... avg_rating=Avg("rating"), ... sample_headline=sample_headline, ... )Поддерживается в SQLite, MySQL, Oracle и PostgreSQL 16+.
MySQL с включённым режимом
ONLY_FULL_GROUP_BYЕсли в MySQL включён режим SQL
ONLY_FULL_GROUP_BY, может потребоваться использоватьAnyValue, когда агрегирование включает сочетание агрегатных и неагрегатных функций. ИспользованиеAnyValueпозволяет ссылаться на неагрегатную функцию в списке выборки, если база данных не может определить, что эта функция функционально зависит от столбцов в предложении GROUP BY. Подробнее см. в документации по агрегированию. - Псевдоним по умолчанию:
Avg
-
class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[исходный код] -
Возвращает среднее значение заданного выражения, которое должно быть числовым, если не указано другое
output_field.- Псевдоним по умолчанию:
<field>__avg - Тип возвращаемого значения:
float, если входное значение —int; в противном случае совпадает с типом входного поля илиoutput_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
-
distinct -
Необязательный параметр. Если
distinct=True,Avgвозвращает среднее значение уникальных значений. Это эквивалент SQL-выраженияAVG(DISTINCT <field>). Значение по умолчанию —False.
- Псевдоним по умолчанию:
Count
-
class Count(expression, distinct=False, filter=None, **extra)[исходный код] -
Возвращает количество объектов, связанных через заданное выражение.
Count('*')эквивалентно SQL-выражениюCOUNT(*).- Псевдоним по умолчанию:
<field>__count - Тип возвращаемого значения:
int
-
distinct -
Необязательный параметр. Если
distinct=True, в подсчёт включаются только уникальные экземпляры. Это эквивалент SQL-выраженияCOUNT(DISTINCT <field>). Значение по умолчанию —False.
Примечание
Аргумент
defaultне поддерживается. - Псевдоним по умолчанию:
Max
-
class Max(expression, output_field=None, filter=None, default=None, **extra)[исходный код] -
Возвращает максимальное значение заданного выражения.
- Псевдоним по умолчанию:
<field>__max - Тип возвращаемого значения: совпадает с типом входного поля или
output_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
- Псевдоним по умолчанию:
Min
-
class Min(expression, output_field=None, filter=None, default=None, **extra)[исходный код] -
Возвращает минимальное значение заданного выражения.
- Псевдоним по умолчанию:
<field>__min - Тип возвращаемого значения: совпадает с типом входного поля или
output_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
- Псевдоним по умолчанию:
StdDev
-
class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)[исходный код] -
Возвращает стандартное отклонение данных в заданном выражении.
- Псевдоним по умолчанию:
<field>__stddev - Тип возвращаемого значения:
float, если входное значение —int; в противном случае совпадает с типом входного поля илиoutput_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
-
sample -
Необязательный параметр. По умолчанию
StdDevвозвращает стандартное отклонение генеральной совокупности. Однако, еслиsample=True, возвращаемым значением будет выборочное стандартное отклонение.
- Псевдоним по умолчанию:
Sum
-
class Sum(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[исходный код] -
Вычисляет сумму всех значений заданного выражения.
- Псевдоним по умолчанию:
<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)[исходный код] -
Возвращает дисперсию данных в заданном выражении.
- Псевдоним по умолчанию:
<field>__variance - Тип возвращаемого значения:
float, если входное значение —int; в противном случае совпадает с типом входного поля илиoutput_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
-
sample -
Необязательный параметр. По умолчанию
Varianceвозвращает дисперсию генеральной совокупности. Однако, еслиsample=True, возвращаемым значением будет выборочная дисперсия.
- Псевдоним по умолчанию:
StringAgg
-
class StringAgg(expression, delimiter, output_field=None, distinct=False, filter=None, order_by=None, default=None, **extra)[исходный код] -
Возвращает входные значения, объединённые в строку и разделённые строкой
delimiter, илиdefault, если значений нет.- Псевдоним по умолчанию:
<field>__stringagg - Тип возвращаемого значения:
stringилиoutput_field, если он задан. Если набор запросов или группа пусты, возвращаетсяdefault.
-
delimiter -
Объект
Valueили выражение, представляющее строку-разделитель между значениями. Например,Value(",").
- Псевдоним по умолчанию:
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/models/querysets/