Справочник API QuerySet
В этом документе описываются детали API QuerySet. Он основан на материалах, представленных в руководствах по моделям и запросам к базе данных, поэтому перед чтением этого документа рекомендуется ознакомиться и понять эти руководства.
В этом справочнике мы будем использовать примеры моделей блога, представленные в руководстве по запросам к базе данных.
Когда QuerySets вычисляются
Внутренне, QuerySet можно создать, отфильтровать, разбить на части и в целом передавать без фактического обращения к базе данных. Никакой активности базы данных не происходит до тех пор, пока вы не выполните какое-либо действие для оценки queryset.
Вы можете оценить QuerySet следующим образом:
-
Итерация.
QuerySetитерируемый, и он выполняет свой запрос к базе данных при первой итерации по нему. Например, это выведет заголовки всех записей в базе данных:for e in Entry.objects.all(): print(e.headline)Примечание: Не используйте этот способ, если вам нужно только определить, существует ли хотя бы один результат. Для этого эффективнее использовать
exists(). -
Асинхронная итерация.
QuerySetтакже можно перебирать с использованиемasync for:async for e in Entry.objects.all(): results.append(e)Синхронные и асинхронные итераторы 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(). Вызвать
list(), чтобы принудительно оценитьQuerySet. Например:entry_list = list(Entry.objects.all())
-
bool(). Тестирование
QuerySetв контексте булевых значений, таком как использованиеbool(),or,andили оператораif, вызовет выполнение запроса. Если существует хотя бы один результат, тоQuerySetимеет значениеTrue, в противном случаеFalse. Например:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")Примечание: Если вам нужно только определить, существует ли хотя бы один результат (и вам не нужны сами объекты), эффективнее использовать
exists().
Сериализация QuerySets
Если вы pickle QuerySet, это принудительно загрузит все результаты в память перед сериализацией. Сериализация обычно используется как предшественник кэшированию, и когда кэшированный queryset загружается повторно, вы хотите, чтобы результаты уже присутствовали и были готовы к использованию (чтение из базы данных может занимать некоторое время, что делает кэширование бесполезным). Это означает, что при рассериализации QuerySet, он содержит результаты на момент сериализации, а не результаты, которые в настоящее время находятся в базе данных.
Если вы хотите сериализовать только необходимую информацию для восстановления QuerySet из базы данных в более позднее время, сериализуйте атрибут query QuerySet. Затем вы можете восстановить исходный QuerySet (без загруженных результатов) с помощью кода, подобного этому:
>>> import pickle >>> query = pickle.loads(s) # Assuming 's' is the pickled string. >>> qs = MyModel.objects.all() >>> qs.query = query # Restore the original 'query'.
Атрибут query — это непрозрачный объект. Он представляет внутреннее состояние построения запроса и не является частью публичного API. Тем не менее, безопасно (и полностью поддерживается) сериализовать и десериализовать содержимое атрибута, как описано здесь.
Ограничения на 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. Эти методы подробно рассматриваются позже в этом разделе.Класс
QuerySetимеет следующие публичные атрибуты, которые можно использовать для интроспекции:-
ordered -
TrueеслиQuerySetотсортирован — т.е. имеет условиеorder_by()или по умолчанию сортировку модели.Falseв противном случае.
-
db -
База данных, которая будет использоваться, если этот запрос будет выполнен сейчас.
Примечание
Параметр
queryдляQuerySetсуществует для того, чтобы специализированные подклассы запросов могли восстановить внутреннее состояние запроса. Значение параметра — непрозрачное представление этого состояния запроса и не является частью публичного API. -
Методы, возвращающие новые QuerySets
Django предоставляет ряд методов уточнения QuerySet , которые изменяют либо типы результатов, возвращаемых QuerySet, либо способ выполнения SQL-запроса.
Примечание
Эти методы не выполняют запросы к базе данных, поэтому они безопасны для использования в асинхронном коде и не имеют отдельных асинхронных версий.
filter()
-
filter(*args, **kwargs)
Возвращает новый QuerySet , содержащий объекты, соответствующие заданным параметрам поиска.
Параметры поиска (**kwargs) должны быть в формате, описанном в Поисках по полям ниже. Несколько параметров объединяются через AND в базовом SQL-запросе.
Если вам нужны более сложные запросы (например, запросы с OR выражениями), вы можете использовать Q objects (*args).
exclude()
-
exclude(*args, **kwargs)
Возвращает новый QuerySet , содержащий объекты, которые не соответствуют заданным параметрам поиска.
Параметры поиска (**kwargs) должны быть в формате, описанном в Поисках по полям ниже. Несколько параметров объединяются через AND в базовом SQL-запросе, и всё это заключено в NOT().
В этом примере исключаются все записи, дата pub_date которых позже 2005-01-03 И чьё значение headline равно “Hello”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline="Hello")
В терминах SQL это эквивалентно:
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
Этот пример исключает все записи, чей pub_date позже 2005-01-03 ИЛИ чей заголовок равен «Hello»:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline="Hello")
В терминах SQL это эквивалентно:
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
Обратите внимание, что второй пример более ограничительный.
Если вам нужно выполнить более сложные запросы (например, запросы с OR операторами), вы можете использовать Q objects (*args).
annotate()
-
annotate(*args, **kwargs)
Добавляет к каждому объекту в QuerySet предоставленный список выражений запроса. Выражение может быть простым значением, ссылкой на поле в модели (или любых связанных моделей), или агрегатным выражением (среднее, сумма и т.д.), которое было вычислено по объектам, связанным с объектами в QuerySet.
Каждый аргумент к annotate() представляет собой аннотацию, которая будет добавлена к каждому объекту в QuerySet который возвращается.
Функции агрегирования, предоставляемые Django, описаны в Функциях агрегирования ниже.
Аннотации, указанные с помощью именованных аргументов, будут использовать имя аргумента в качестве псевдонима для аннотации. Анонимные аргументы будут иметь псевдоним, сгенерированный на основе имени функции агрегации и поля модели, которое агрегируется. Только агрегатные выражения, ссылающиеся на одно поле, могут быть анонимными аргументами. Всё остальное должно быть именованным аргументом.
Например, если вы работаете со списком блогов, вы можете захотеть определить, сколько записей было сделано в каждом блоге:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count("entry"))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Модель Blog не определяет атрибут entry__count сама по себе, но с помощью именованного аргумента для указания функции агрегации, вы можете контролировать имя аннотации:
>>> q = Blog.objects.annotate(number_of_entries=Count("entry"))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
Для углублённого обсуждения агрегации, см. руководство по теме Агрегирования.
alias()
-
alias(*args, **kwargs)
То же, что и annotate(), но вместо аннотации объектов в QuerySet, сохраняет выражение для последующего повторного использования с другими QuerySet методами. Это полезно, когда результат самого выражения не нужен, но он используется для фильтрации, сортировки или как часть сложного выражения. Невыборка ненужного значения уменьшает избыточную работу в базе данных, что должно привести к лучшей производительности.
Например, если вы хотите найти блоги с более чем 5 записями, но не заинтересованы в точном количестве записей, вы можете сделать это:
>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count("entry")).filter(entries__gt=5)
alias() может использоваться совместно с annotate(), exclude(), filter(), order_by() и update(). Для использования алиасированного выражения с другими методами (например, aggregate()), вы должны повысить его до аннотации:
Blog.objects.alias(entries=Count("entry")).annotate(
entries=F("entries"),
).aggregate(Sum("entries"))
filter() и order_by() могут принимать выражения напрямую, но построение и использование выражений часто не происходит в одном месте (например, метод QuerySet создает выражения для последующего использования в представлениях). alias() позволяет создавать сложные выражения по частям, возможно, охватывая несколько методов и модулей, ссылаться на части выражения по их псевдонимам и использовать только annotate() для конечного результата.
order_by()
-
order_by(*fields)
По умолчанию результаты, возвращаемые QuerySet сортируются по кортежу сортировки, заданному опцией ordering в Meta модели. Вы можете переопределить это для каждого QuerySet используя метод order_by.
Пример:
Entry.objects.filter(pub_date__year=2005).order_by("-pub_date", "headline")
Результат выше будет отсортирован по pub_date в убывающем порядке, затем по headline в возрастающем порядке. Минус перед "-pub_date" указывает на убывающий порядок. Возрастающий порядок подразумевается. Для случайной сортировки используйте "?", как показано ниже:
Entry.objects.order_by("?")
Примечание: запросы сортировки по случайному принципу могут быть дорогостоящими и медленными, в зависимости от используемого вами бэкенда базы данных.
Чтобы отсортировать по полю в другой модели, используйте ту же синтаксическую конструкцию, что и при запросах через связи между моделями. То есть, имя поля, за которым следует двойное подчеркивание (__), а затем имя поля в новой модели, и так далее для всех необходимых соединений моделей. Например:
Entry.objects.order_by("blog__name", "headline")
Если вы попытаетесь отсортировать по полю, являющемуся отношением к другой модели, Django будет использовать стандартный порядок сортировки связанной модели или сортировать по первичному ключу связанной модели, если не указано Meta.ordering. Например, так как модель Blog не имеет заданного стандартного порядка сортировки:
Entry.objects.order_by("blog")
…тождественно:
Entry.objects.order_by("blog__id")
Если бы Blog имела ordering = ['name'], то первый набор результатов был бы идентичен:
Entry.objects.order_by("blog__name")
Вы также можете отсортировать по выражениям запроса вызвав asc() или desc() для выражения:
Entry.objects.order_by(Coalesce("summary", "headline").desc())
asc() и desc() имеют аргументы (nulls_first и nulls_last), которые контролируют порядок сортировки значений NULL.
Будьте осторожны при сортировке по полям в связанных моделях, если вы также используете distinct(). См. примечание в distinct() для объяснения того, как порядок сортировки связанной модели может изменить ожидаемые результаты.
Примечание
Разрешается указать многозначное поле для сортировки результатов (например, поле ManyToManyField или обратное отношение поля ForeignKey).
Рассмотрим такой случай:
class Event(Model):
parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
related_name="children",
)
date = models.DateField()
Event.objects.order_by("children__date")
В данном случае может быть несколько данных сортировки для каждого Event; каждый Event с несколькими children будет возвращен несколько раз в новый QuerySet, который order_by() создаёт. Другими словами, использование order_by() на QuerySet может вернуть больше элементов, чем вы изначально работали с - что, вероятно, не ожидается и не является полезным.
Поэтому будьте внимательны, когда используете многозначные поля для сортировки результатов. **Если** вы можете быть уверены, что для каждого элемента, по которому вы сортируете, будет только один элемент сортировки, этот подход не должен вызывать проблем. Если нет, убедитесь, что результаты соответствуют вашим ожиданиям.
Нет способа указать, должна ли сортировка быть регистрозависимой. Что касается регистрозависимости, Django отсортирует результаты так, как это обычно делает ваш бэкенд базы данных.
Вы можете отсортировать по полю, преобразованному в нижний регистр с помощью Lower, что обеспечит согласованную сортировку по регистру:
Entry.objects.order_by(Lower("headline").desc())
Если вы не хотите, чтобы к запросу применялась какая-либо сортировка, даже по умолчанию, вызовите order_by() без параметров.
Вы можете узнать, отсортирован ли запрос или нет, проверив атрибут QuerySet.ordered, который будет True если QuerySet был отсортирован каким-либо образом.
Каждый вызов order_by() очистит предыдущую сортировку. Например, этот запрос будет отсортирован по pub_date, а не по headline:
Entry.objects.order_by("headline").order_by("pub_date")
Предупреждение
Сортировка — это не бесплатная операция. Каждое поле, которое вы добавляете в сортировку, влечёт за собой затраты для вашей базы данных. Каждое внешнее ключевое поле, которое вы добавляете, также подразумевает включение всех его стандартных сортировок.
Если в запросе не указана сортировка, результаты возвращаются из базы данных в неопределённом порядке. Конкретная сортировка гарантируется только при сортировке по набору полей, которые однозначно идентифицируют каждый объект в результатах. Например, если поле name не является уникальным, сортировка по нему не гарантирует, что объекты с одинаковым именем всегда будут отображаться в одинаковом порядке.
reverse()
-
reverse()
Используйте метод reverse() для изменения порядка возврата элементов набора запросов. Вызов reverse() второй раз восстанавливает порядок обратно к нормальному направлению.
Чтобы получить последние пять элементов в наборе запросов, можно сделать так:
my_queryset.reverse()[:5]
Обратите внимание, что это не совсем то же самое, что извлечение среза с конца последовательности в Python. Приведённый выше пример вернёт последний элемент в первую очередь, затем предпоследний и так далее. Если бы у нас была последовательность Python и мы бы посмотрели на seq[-5:], мы бы увидели предпоследний элемент в первую очередь. Django не поддерживает этот режим доступа (извлечение среза с конца), потому что это неэффективно в SQL.
Также обратите внимание, что reverse() в целом следует вызывать только на наборе запросов QuerySet, который имеет определённую сортировку (например, при запросе к модели, которая определяет стандартную сортировку, или при использовании order_by()). Если такая сортировка не определена для данного набора запросов QuerySet, вызов reverse() на нём не окажет реального влияния (сортировка была неопределённой до вызова reverse(), и останется неопределённой после этого).
distinct()
-
distinct(*fields)
Возвращает новый набор запросов QuerySet, который использует SELECT DISTINCT в своём SQL-запросе. Это устраняет дубликаты строк из результатов запроса.
По умолчанию набор запросов QuerySet не удаляет дубликаты строк. На практике это редко вызывает проблему, поскольку простые запросы, такие как Blog.objects.all(), не создают возможности получения дублирующих строк результатов. Однако, если ваш запрос охватывает несколько таблиц, возможно получение дубликатов результатов, когда вычисляется набор запросов QuerySet. В этом случае вы должны использовать distinct().
Примечание
Любые поля, используемые в вызове order_by(), включаются в столбцы SQL SELECT. Это иногда приводит к неожиданным результатам при совместном использовании с distinct(). Если вы сортируете по полям связанной модели, эти поля будут добавлены в выбранные столбцы, и они могут заставить иначе дублирующиеся строки казаться отличными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они присутствуют только для поддержки сортировки), иногда кажется, что возвращаются не дублированные результаты.
Аналогично, если вы используете запрос values() для ограничения выбранных столбцов, столбцы, используемые в любом order_by() (или стандартная сортировка модели), всё ещё будут участвовать и могут повлиять на уникальность результатов.
Вывод в данном случае состоит в том, что если вы используете distinct(), будьте осторожны при сортировке по связанным моделям. Аналогично, при совместном использовании distinct() и values(), будьте осторожны при сортировке по полям, не включённым в вызов values().
Только в PostgreSQL вы можете передавать позиционные аргументы (*fields) для указания имён полей, к которым должна применяться DISTINCT. Это переводится в запрос SQL SELECT DISTINCT ON. Вот в чём разница. В обычном вызове distinct(), база данных сравнивает каждое поле в каждой строке при определении того, какие строки являются уникальными. В вызове distinct() с указанными именами полей база данных будет сравнивать только указанные имена полей.
Примечание
Когда вы указываете имена полей, вы обязательно должны предоставить order_by() в QuerySet, а поля в order_by() должны начинаться с полей в distinct(), в том же порядке.
Например, SELECT DISTINCT ON (a) даёт вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите какую-то произвольную строку.
Примеры (те, что после первого, будут работать только в PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by("pub_date").distinct("pub_date")
[...]
>>> Entry.objects.order_by("blog").distinct("blog")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
[...]
>>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author")
[...]
Примечание
Помните, что order_by() использует любые стандартные сортировки связанной модели, которые были определены. Возможно, вам придётся явно отсортировать по отношению _id или указанному полю, чтобы убедиться, что выражения DISTINCT ON соответствуют тем, которые находятся в начале фразы ORDER BY. Например, если модель Blog определила ordering по name:
Entry.objects.order_by("blog").distinct("blog")
…не сработает, потому что запрос будет отсортирован по blog__name, что не соответствует выражениям DISTINCT ON. Вам нужно будет явно отсортировать по отношению _id полю (blog_id в данном случае) или по связанному (blog__pk) полю, чтобы убедиться, что оба выражения совпадают.
values()
-
values(*fields, **expressions)
Возвращает набор запросов QuerySet, который возвращает словари, а не экземпляры модели, при использовании в качестве итерируемого объекта.
Каждый из этих словарей представляет объект, где ключи соответствуют именам атрибутов объектов модели.
Этот пример сравнивает словари values() с обычными объектами модели:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Метод values() принимает необязательные позиционные аргументы, *fields, которые определяют имена полей, к которым должен быть ограничен набор запросов SELECT. Если вы указываете поля, каждый словарь будет содержать только ключи/значения полей, которые вы указали. Если вы не указываете поля, каждый словарь будет содержать ключ и значение для каждого поля в таблице базы данных.
Пример:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Метод values() также принимает необязательные ключевые аргументы, **expressions, которые передаются в annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
Вы можете использовать встроенные и пользовательские функции в сортировке. Например:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>
Агрегат в фразе values() применяется до других аргументов в той же фразе values(). Если вам нужно сгруппировать по другому значению, добавьте его в предыдущую фразу values() вместо этого. Например:
>>> from django.db.models import Count
>>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
Несколько тонкостей, которые стоит упомянуть:
-
Если у вас есть поле, называемое
foo, которое являетсяForeignKey, вызов по умолчаниюvalues()вернёт ключ словаряfoo_id, так как это имя скрытого атрибута модели, хранящего фактическое значение (атрибутfooссылается на связанную модель). При вызовеvalues()и передаче имён полей, вы можете передать либоfoo, либоfoo_id, и получите то же самое (ключ словаря будет соответствовать имени поля, которое вы передали).Например:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values("blog") <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values("blog_id") <QuerySet [{'blog_id': 1}, ...]> - При использовании
values()вместе сdistinct(), имейте в виду, что сортировка может повлиять на результаты. См. примечание вdistinct()для получения подробностей. - Если вы используете предложение
values()после вызоваextra(), любые поля, определённые аргументомselectв вызовеextra(), должны быть явно включены в вызовvalues(). Любой вызовextra(), сделанный после вызоваvalues(), проигнорирует дополнительные выбранные поля. - Вызов
only()иdefer()послеvalues()не имеет смысла, поэтому это приведёт к исключениюTypeError. -
Объединение преобразований и агрегаций требует использования двух вызовов
annotate(), явно или в качестве ключевых аргументов дляvalues(). Как и выше, если преобразование зарегистрировано для соответствующего типа поля, первый вызовannotate()можно опустить, поэтому следующие примеры эквивалентны:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values("entry__authors__name__lower").annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values(entry__authors__name__lower=Lower("entry__authors__name")).annotate( ... entries=Count("entry") ... ) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate(entry__authors__name__lower=Lower("entry__authors__name")).values( ... "entry__authors__name__lower" ... ).annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
Это полезно, когда вам нужны значения только из небольшого числа доступных полей, и вам не нужна функциональность объекта модели. Более эффективно выбрать только необходимые поля.
Наконец, обратите внимание, что вы можете вызвать filter(), order_by(), и т.д. после вызова values(), что означает, что эти два вызова идентичны:
Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()
Авторы Django предпочитают располагать все методы, влияющие на SQL, первыми, за которыми (по желанию) следуют методы, влияющие на вывод (такие как values()), но это не имеет решающего значения. Это ваш шанс продемонстрировать свою индивидуальность.
Вы также можете ссылаться на поля связанных моделей с обратными отношениями через атрибуты OneToOneField, ForeignKey и ManyToManyField:
>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Предупреждение
Поскольку атрибуты ManyToManyField и обратные отношения могут иметь несколько связанных строк, их включение может привести к увеличению размера набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в запрос values(), в таком случае будут возвращены все возможные комбинации.
Специальные значения для JSONField в SQLite
Из-за реализации функций JSON_EXTRACT и JSON_TYPE в SQLite и отсутствия типа данных BOOLEAN, values() вернёт True, False, и None вместо "true", "false", и "null" строк для преобразований ключей поля JSONField.
values_list()
-
values_list(*fields, flat=False, named=False)
Это аналогично values() за исключением того, что вместо словарей он возвращает кортежи при итерации. Каждый кортеж содержит значение из соответствующего поля или выражения, переданного в вызов values_list() — первый элемент соответствует первому полю и т.д. Например:
>>> Entry.objects.values_list("id", "headline")
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list("id", Lower("headline"))
<QuerySet [(1, 'first entry'), ...]>
Если вы передаёте только одно поле, вы также можете передать параметр flat. Если True, это означает, что возвращаемые результаты будут отдельными значениями, а не кортежами из одного элемента. Пример позволит прояснить разницу:
>>> Entry.objects.values_list("id").order_by("id")
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list("id", flat=True).order_by("id")
<QuerySet [1, 2, 3, ...]>
Ошибка возникает при передаче flat при наличии более одного поля.
Вы можете передать named=True для получения результатов в виде namedtuple():
>>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
Использование именованного кортежа может сделать использование результатов более читаемым, за счёт небольшой потери производительности при преобразовании результатов в именованный кортеж.
Если вы не передаёте никаких значений в values_list(), он вернёт все поля модели в порядке их объявления.
Частая потребность заключается в получении определённого значения поля конкретного экземпляра модели. Для этого используйте values_list() и вызов get():
>>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'
values() и values_list() предназначены в качестве оптимизаций для конкретного случая использования: извлечение подмножества данных без накладных расходов на создание экземпляра модели. Эта метафора перестаёт работать при работе с отношениями "многие ко многим" и другими многозначными отношениями (такими как отношения "один ко многим" обратного внешнего ключа), так как предположение "одна строка, один объект" не выполняется.
Например, обратите внимание на поведение при запросе через ManyToManyField:
>>> Author.objects.values_list("name", "entry__headline")
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
Авторы с несколькими записями появляются несколько раз, а авторы без записей имеют None для заголовка записи.
Аналогично, при запросе обратного внешнего ключа None появляется для записей без автора:
>>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
Специальные значения для JSONField в SQLite
Из-за реализации функций JSON_EXTRACT и JSON_TYPE в SQLite и отсутствия типа данных BOOLEAN, values_list() вернёт True, False, и None вместо "true", "false", и "null" строк для преобразований ключей поля JSONField.
dates()
-
dates(field, kind, order='ASC')
Возвращает QuerySet, содержащий список объектов datetime.date, представляющих все доступные даты определённого типа в содержимом QuerySet.
field должно быть именем DateField вашей модели. kind должно быть "year", "month", "week", или "day". Каждый объект datetime.date в списке результатов «обрезается» до заданного type.
-
"year"возвращает список всех уникальных значений года для поля. -
"month"возвращает список всех уникальных значений год/месяц для поля. -
"week"возвращает список всех уникальных значений год/неделя для поля. Все даты будут понедельниками. -
"day"возвращает список всех уникальных значений год/месяц/день для поля.
order, по умолчанию 'ASC', должно быть либо 'ASC', либо 'DESC'. Это определяет порядок результатов.
Примеры:
>>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]
datetimes()
-
datetimes(field_name, kind, order='ASC', tzinfo=None)
Возвращает 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() создаст набор запросов, который никогда не вернёт ни одного объекта, и ни один запрос не будет выполнен при обращении к результатам. Набор запросов qs.none() является экземпляром EmptyQuerySet.
Примеры:
>>> Entry.objects.none() <QuerySet []> >>> from django.db.models.query import EmptyQuerySet >>> isinstance(Entry.objects.none(), EmptyQuerySet) True
all()
-
all()
Возвращает копию текущего набора запросов (или подкласса набора запросов) QuerySet (или подкласса QuerySet). Это может быть полезно в ситуациях, когда вы хотите передать менеджер модели или набор запросов QuerySet и выполнить дополнительную фильтрацию результата. После вызова all() для любого объекта вы обязательно получите набор запросов QuerySet для работы.
Когда набор запросов QuerySet оценивается, он обычно кэширует свои результаты. Если данные в базе данных могли измениться с момента оценки набора запросов QuerySet, вы можете получить обновлённые результаты для того же запроса, вызвав all() на ранее оцененном наборе запросов QuerySet.
union()
-
union(*other_qs, all=False)
Использует оператор SQL UNION для объединения результатов двух или более наборов запросов QuerySet.
>>> qs1.union(qs2, qs3)
Оператор UNION по умолчанию выбирает только уникальные значения. Чтобы разрешить дубликаты, используйте аргумент all=True.
union(), intersection(), и difference() возвращают экземпляры моделей типа первого набора запросов QuerySet, даже если аргументы — наборы запросов QuerySet других моделей. Передача разных моделей работает, если список SELECT одинаков во всех наборах запросов QuerySet (по крайней мере, типы, имена не важны, если типы в том же порядке). В таких случаях вы должны использовать имена столбцов из первого набора запросов QuerySet в методах QuerySet, применённых к результирующему набору запросов QuerySet. Например:
>>> qs1 = Author.objects.values_list("name")
>>> qs2 = Entry.objects.values_list("headline")
>>> qs1.union(qs2).order_by("name")
Кроме того, разрешены только LIMIT, OFFSET, COUNT(*), ORDER BY, и указание столбцов (т.е., срез, count(), exists(), order_by() и values()/values_list()) на результирующем наборе запросов QuerySet. Кроме того, базы данных накладывают ограничения на разрешённые операции в объединённых запросах. Например, большинство баз данных не позволяют LIMIT или OFFSET в объединённых запросах.
intersection()
-
intersection(*other_qs)
Использует оператор SQL INTERSECT для возвращения общих элементов двух или более наборов запросов QuerySet.
>>> qs1.intersection(qs2, qs3)
См. union() для некоторых ограничений.
difference()
-
difference(*other_qs)
Использует оператор SQL EXCEPT для сохранения только элементов, присутствующих в QuerySet, но не в других наборах запросов QuerySet.
>>> qs1.difference(qs2, qs3)
См. union() для некоторых ограничений.
select_related()
Возвращает набор запросов QuerySet, который будет «следовать» зависимостям внешних ключей, выбирая дополнительные связанные данные при выполнении запроса. Это ускоряет работу, в результате чего выполняется один более сложный запрос, но последующее использование зависимостей внешних ключей не потребует запросов к базе данных.
Следующие примеры иллюстрируют разницу между обычными запросами и запросами с select_related().
# Hits the database. e = Entry.objects.get(id=5) # Hits the database again to get the related Blog object. b = e.blog
И вот запрос с select_related:
# Hits the database.
e = Entry.objects.select_related("blog").get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
Вы можете использовать select_related() с любым набором запросов объектов:
from django.utils import timezone
# Find all the blogs with entries scheduled to be published in the future.
blogs = set()
for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog"):
# Without select_related(), this would make a database query for each
# loop iteration in order to fetch the related blog for each entry.
blogs.add(e.blog)
Порядок цепочки вызовов filter() и select_related() не имеет значения. Эти наборы запросов эквивалентны:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog")
Entry.objects.select_related("blog").filter(pub_date__gt=timezone.now())
Вы можете следовать внешним ключам аналогичным образом, как запросы к ним. Если у вас есть следующие модели:
from django.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(
City,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
class Book(models.Model):
# ...
author = models.ForeignKey(Person, on_delete=models.CASCADE)
… то вызов Book.objects.select_related('author__hometown').get(id=4) кэширует связанные Person и связанные City:
# Hits the database with joins to the author and hometown tables.
b = Book.objects.select_related("author__hometown").get(id=4)
p = b.author # Doesn't hit the database.
c = p.hometown # Doesn't hit the database.
# Without select_related()...
b = Book.objects.get(id=4) # Hits the database.
p = b.author # Hits the database.
c = p.hometown # Hits the database.
Вы можете ссылаться на любое отношение ForeignKey или OneToOneField в списке полей, переданном в select_related().
Вы также можете обратиться к обратному направлению OneToOneField в списке полей, переданном в select_related — то есть вы можете пройти по OneToOneField обратно к объекту, в котором определено поле. Вместо указания имени поля, используйте related_name для поля на связанном объекте.
Возможны ситуации, когда вы хотите вызвать select_related() с большим количеством связанных объектов или когда вы не знаете всех отношений. В таких случаях можно вызвать select_related() без аргументов. Это позволит следовать всем непустым внешним ключам, которые могут быть найдены – пустые внешние ключи должны быть указаны. В большинстве случаев это не рекомендуется, так как, вероятно, это сделает базовый запрос более сложным и вернёт больше данных, чем необходимо.
Если вам нужно очистить список связанных полей, добавленных прошлыми вызовами select_related для набора запросов QuerySet, вы можете передать None в качестве параметра:
>>> without_relations = queryset.select_related(None)
Цепочка вызовов select_related работает аналогично другим методам – select_related('foo', 'bar') эквивалентно select_related('foo').select_related('bar').
prefetch_related()
Возвращает набор запросов QuerySet, который автоматически получит, в одной партии, связанные объекты для каждого из указанных запросов.
Это имеет аналогичную цель с select_related, поскольку оба предназначены для предотвращения потока запросов к базе данных, вызванных доступом к связанным объектам, но стратегия совершенно отличается.
select_related работает путём создания объединения SQL и включения полей связанного объекта в оператор SELECT . Таким образом, select_related получает связанные объекты в одном запросе к базе данных. Однако, чтобы избежать намного большего набора результатов, который бы получился при объединении по отношению «многие-ко-многим», select_related ограничивается отношениями со значением 1 – внешними ключами и ключами «один к одному».
prefetch_related, с другой стороны, выполняет отдельный поиск для каждой связи и выполняет «соединение» в Python. Это позволяет предварительно загружать объекты «многие ко многим», «многие к одному» и GenericRelation, чего нельзя сделать с помощью select_related, помимо внешних ключей и связей «один к одному», поддерживаемых select_related. Он также поддерживает предварительную загрузку GenericForeignKey, однако набор запросов для каждого ContentType должен быть предоставлен в параметре querysets объекта GenericPrefetch.
Добавлена поддержка предварительной загрузки GenericForeignKey с неоднородным набором результатов.
Например, предположим, что у вас есть эти модели:
from django.db import models
class Topping(models.Model):
name = models.CharField(max_length=30)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
def __str__(self):
return "%s (%s)" % (
self.name,
", ".join(topping.name for topping in self.toppings.all()),
)
и выполняется:
>>> Pizza.objects.all() ["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
Проблема в том, что каждый раз, когда Pizza.__str__() запрашивает self.toppings.all(), ему необходимо выполнить запрос к базе данных, поэтому Pizza.objects.all() выполнит запрос к таблице Toppings для каждого элемента в Pizza QuerySet.
Мы можем уменьшить это до двух запросов, используя prefetch_related:
>>> Pizza.objects.prefetch_related("toppings")
Это подразумевает self.toppings.all() для каждого Pizza; теперь каждый раз, когда self.toppings.all() вызывается, вместо того, чтобы обращаться к базе данных за элементами, он найдёт их в кэше предварительно загруженных QuerySet объектов, который был заполнен в одном запросе.
То есть, все соответствующие дополнения будут извлечены в одном запросе и использованы для создания QuerySets объектов, у которых имеется заполненный кэш соответствующих результатов; эти QuerySets затем используются в вызовах self.toppings.all().
Дополнительные запросы в prefetch_related() выполняются после того, как QuerySet начал оцениваться, и основной запрос был выполнен.
Обратите внимание, что нет механизма предотвращения изменения данных в базе данных между выполнением основного запроса и дополнительных запросов, что может привести к несогласованному результату. Например, если Pizza удаляется после выполнения основного запроса, его дополнения не будут возвращены в дополнительном запросе, и покажется, что у пиццы нет дополнений:
>>> Pizza.objects.prefetch_related("toppings")
# "Hawaiian" Pizza was deleted in another shell.
<QuerySet [<Pizza: Hawaiian ()>, <Pizza: Seafood (prawns, smoked salmon)>]>
Если у вас есть итерируемый список экземпляров моделей, вы можете предварительно загрузить связанные атрибуты этих экземпляров с помощью функции prefetch_related_objects().
Обратите внимание, что кэш результатов основного QuerySet и всех указанных связанных объектов будет полностью загружен в память. Это изменяет типичное поведение QuerySets, которые обычно пытаются избегать загрузки всех объектов в память до их необходимости, даже после выполнения запроса в базе данных.
Примечание
Помните, что, как всегда при использовании QuerySets, любые последующие связанные методы, которые подразумевают другой запрос к базе данных, проигнорируют ранее кэшированные результаты и извлекут данные с помощью нового запроса к базе данных. Таким образом, если вы напишете следующее:
>>> pizzas = Pizza.objects.prefetch_related("toppings")
>>> [list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
…то тот факт, что pizza.toppings.all() был предварительно загружен, не поможет вам. prefetch_related('toppings') подразумевает pizza.toppings.all(), но pizza.toppings.filter() — это новый и другой запрос. Кэшированные предварительно загруженные данные здесь не помогут; на самом деле, это вредит производительности, поскольку вы выполнили запрос к базе данных, который не использовали. Поэтому используйте эту функцию с осторожностью!
Также, если вы вызываете методы изменения базы данных add(), remove(), clear() или set() для related managers, кэш предварительной загрузки для связи будет очищен.
Вы также можете использовать обычный синтаксис соединения для связанных полей связанных полей. Предположим, что у нас есть дополнительная модель к приведенному выше примеру:
class Restaurant(models.Model):
pizzas = models.ManyToManyField(Pizza, related_name="restaurants")
best_pizza = models.ForeignKey(
Pizza, related_name="championed_by", on_delete=models.CASCADE
)
Следующие являются допустимыми:
>>> Restaurant.objects.prefetch_related("pizzas__toppings")
Это предварительно загрузит все пиццы, принадлежащие ресторанам, и все дополнения, принадлежащие этим пиццам. Это приведет к общему количеству запросов к базе данных в 3 — один для ресторанов, один для пицц и один для дополнений.
>>> Restaurant.objects.prefetch_related("best_pizza__toppings")
Это извлечёт лучшую пиццу и все дополнения к лучшей пицце для каждого ресторана. Это будет выполнено в 3 запросах к базе данных — один для ресторанов, один для «лучших пицц» и один для дополнений.
Связь best_pizza также может быть извлечена, используя select_related , чтобы уменьшить количество запросов до 2:
>>> Restaurant.objects.select_related("best_pizza").prefetch_related("best_pizza__toppings")
Поскольку предварительная загрузка выполняется после основного запроса (включающего соединения, необходимые для select_related), она способна определить, что объекты best_pizza уже были извлечены, и она пропустит их повторное извлечение.
Цепочечные вызовы prefetch_related будут накапливать запросы, которые будут предварительно загружаться. Чтобы очистить поведение prefetch_related , передайте None в качестве параметра:
>>> non_prefetched = qs.prefetch_related(None)
Одно отличие, которое следует отметить при использовании prefetch_related , заключается в том, что объекты, созданные запросом, могут быть разделены между различными объектами, к которым они относятся, т. е. один экземпляр модели Python может появиться более чем в одном месте в дереве возвращаемых объектов. Это обычно происходит с внешними ключами. Обычно это поведение не будет проблемой и фактически сэкономит как память, так и время ЦП.
Хотя prefetch_related поддерживает предварительную загрузку GenericForeignKey связей, количество запросов будет зависеть от данных. Поскольку GenericForeignKey может ссылаться на данные в нескольких таблицах, требуется по одному запросу на каждую таблицу, на которую есть ссылка, а не один запрос на все элементы. Может быть несколько дополнительных запросов к таблице ContentType , если соответствующие строки ещё не извлечены.
prefetch_related в большинстве случаев будет реализовано с помощью SQL-запроса, использующего оператор «IN». Это означает, что для большого QuerySet может быть сгенерирована большая клауза «IN», которая, в зависимости от базы данных, может иметь свои собственные проблемы с производительностью при разборе или выполнении SQL-запроса. Всегда производите профилирование для вашего случая использования!
Если вы используете iterator() для выполнения запроса, вызовы prefetch_related() будут наблюдаться только в том случае, если предоставлено значение для chunk_size.
Вы можете использовать объект Prefetch для дальнейшего управления операцией предварительной загрузки.
В самом простом виде Prefetch эквивалентен традиционным поисковым запросам на основе строк:
>>> from django.db.models import Prefetch
>>> Restaurant.objects.prefetch_related(Prefetch("pizzas__toppings"))
Вы можете предоставить набор запросов с необязательным аргументом queryset. Это может быть использовано для изменения стандартного упорядочения набора запросов:
>>> Restaurant.objects.prefetch_related(
... Prefetch("pizzas__toppings", queryset=Toppings.objects.order_by("name"))
... )
Или для вызова select_related(), когда это возможно, чтобы ещё больше уменьшить количество запросов:
>>> Pizza.objects.prefetch_related(
... Prefetch("restaurants", queryset=Restaurant.objects.select_related("best_pizza"))
... )
Вы также можете назначить предварительно загруженный результат на пользовательский атрибут с необязательным аргументом to_attr. Результат будет сохранён непосредственно в списке.
Это позволяет предварительно загрузить ту же связь несколько раз с различными QuerySet; например:
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
... Prefetch("pizzas", to_attr="menu"),
... Prefetch("pizzas", queryset=vegetarian_pizzas, to_attr="vegetarian_menu"),
... )
Обращения, созданные с пользовательскими to_attr , всё ещё могут быть пройдены обычным способом другими обращениями:
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
... Prefetch("pizzas", queryset=vegetarian_pizzas, to_attr="vegetarian_menu"),
... "vegetarian_menu__toppings",
... )
Использование to_attr рекомендуется при фильтрации результата предварительной загрузки, поскольку это менее неоднозначно, чем сохранение отфильтрованного результата в кэше связанного менеджера:
>>> queryset = Pizza.objects.filter(vegetarian=True)
>>>
>>> # Recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch("pizzas", queryset=queryset, to_attr="vegetarian_pizzas")
... )
>>> vegetarian_pizzas = restaurants[0].vegetarian_pizzas
>>>
>>> # Not recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch("pizzas", queryset=queryset),
... )
>>> vegetarian_pizzas = restaurants[0].pizzas.all()
Пользовательская предварительная загрузка также работает со связанными отношениями, такими как прямые ForeignKey или OneToOneField . В целом, вы захотите использовать select_related() для этих отношений, но есть ряд случаев, когда предварительная загрузка с пользовательским QuerySet полезна:
- Вы хотите использовать
QuerySet, который выполняет дальнейшую предварительную загрузку связанных моделей. - Вы хотите предварительно загрузить только подмножество связанных объектов.
-
Вы хотите использовать методы оптимизации производительности, такие как
deferred fields:>>> queryset = Pizza.objects.only("name") >>> >>> restaurants = Restaurant.objects.prefetch_related( ... Prefetch("best_pizza", queryset=queryset) ... )
При использовании нескольких баз данных Prefetch будет учитывать ваш выбор базы данных. Если внутренний запрос не указывает базу данных, он будет использовать базу данных, выбранную внешним запросом. Все следующие являются допустимыми:
>>> # Both inner and outer queries will use the 'replica' database
>>> Restaurant.objects.prefetch_related("pizzas__toppings").using("replica")
>>> Restaurant.objects.prefetch_related(
... Prefetch("pizzas__toppings"),
... ).using("replica")
>>>
>>> # Inner will use the 'replica' database; outer will use 'default' database
>>> Restaurant.objects.prefetch_related(
... Prefetch("pizzas__toppings", queryset=Toppings.objects.using("replica")),
... )
>>>
>>> # Inner will use 'replica' database; outer will use 'cold-storage' database
>>> Restaurant.objects.prefetch_related(
... Prefetch("pizzas__toppings", queryset=Toppings.objects.using("replica")),
... ).using("cold-storage")
Примечание
Порядок запросов имеет значение.
Рассмотрим следующие примеры:
>>> prefetch_related("pizzas__toppings", "pizzas")
Это работает, даже если порядок не определен, потому что 'pizzas__toppings' уже содержит всю необходимую информацию, поэтому второй аргумент 'pizzas' фактически избыточен.
>>> prefetch_related("pizzas__toppings", Prefetch("pizzas", queryset=Pizza.objects.all()))
Это вызовет ValueError, из-за попытки переопределить набор запросов для ранее увиденного запроса. Обратите внимание, что неявный набор запросов был создан для обхода 'pizzas' в рамках запроса 'pizzas__toppings'.
>>> prefetch_related("pizza_list__toppings", Prefetch("pizzas", to_attr="pizza_list"))
Это вызовет AttributeError, так как 'pizza_list' ещё не существует, когда обрабатывается 'pizza_list__toppings'.
Это соображение не ограничивается использованием Prefetch объектов. Некоторые сложные методы могут потребовать выполнения запросов в определённом порядке, чтобы избежать создания дополнительных запросов; поэтому рекомендуется всегда тщательно упорядочивать аргументы prefetch_related.
extra()
-
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
Иногда синтаксис запросов Django не позволяет легко выразить сложный WHERE условие. В таких случаях Django предоставляет extra() QuerySet модификатор — возможность вставки специфических условий в SQL-запрос, генерируемый QuerySet.
Используйте этот метод в крайнем случае
Это устаревший API, который мы планируем в какой-то момент в будущем устареть. Используйте его только если вы не можете выразить свой запрос с помощью других методов набора запросов. Если вам нужно его использовать, пожалуйста, отправьте заявку с помощью QuerySet.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, Django может изменить этот псевдоним (например, когда набор запросов используется как подзапрос в ещё одном запросе).
Предупреждение
Вы должны быть очень осторожны при использовании extra(). Каждый раз, когда вы его используете, вы должны экранировать любые параметры, которые пользователь может контролировать, используя params для защиты от атак SQL-инъекции.
Вы также не должны заключать в кавычки плейсхолдеры в строке SQL. Этот пример уязвим к SQL-инъекции из-за кавычек вокруг %s:
SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
Вы можете узнать больше о том, как работает защита от атак SQL-инъекции в Django, в разделе Защита от атак SQL-инъекции.
По определению, эти дополнительные запросы могут быть не переносимы на разные базы данных (потому что вы явно пишете SQL-код) и нарушают принцип DRY, поэтому следует избегать их, если это возможно.
Укажите один или несколько из params, select, where или tables. Ни один из аргументов не является обязательным, но вы должны использовать хотя бы один из них.
-
selectАргумент
selectпозволяет добавлять дополнительные поля в условиеSELECT. Он должен быть словарем, сопоставляющим имена атрибутов с SQL-фрагментами, которые нужно использовать для вычисления этого атрибута.Пример:
Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})В результате каждый
Entryобъект будет иметь дополнительный атрибут,is_recent, булево значение, представляющее собой значение того, является ли запись’spub_dateбольше чем 1 января 2006.Django вставляет указанный SQL-фрагмент непосредственно в оператор
SELECT, поэтому результирующий SQL-код в вышеприведённом примере будет чем-то вроде:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Следующий пример более сложный; он использует подзапрос, чтобы предоставить каждому результату
Blogобъекта атрибутentry_count, целое число, представляющее количество связанныхEntryобъектов:Blog.objects.extra( select={ "entry_count": "SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id" }, )В данном случае мы используем тот факт, что запрос уже содержит таблицу
blog_blogв своём условииFROM.Результирующий SQL в приведённом выше примере будет:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Обратите внимание, что круглые скобки, необходимые большинству баз данных для подзапросов, не требуются в
selectусловиях Django. Также обратите внимание, что некоторые базы данных, например, некоторые версии MySQL, не поддерживают подзапросы.В некоторых редких случаях вам может потребоваться передать параметры в фрагменты SQL в
extra(select=...). Для этого используется параметрselect_params.Это будет работать, например:
Blog.objects.extra( select={"a": "%s", "b": "%s"}, select_params=("one", "two"), )Если вам нужно использовать литеральное значение
%sв строке выбора, используйте последовательность%%s. -
where/tablesВы можете определить явные SQL
WHEREусловия — возможно, для выполнения неявных соединений — с помощьюwhere. Вы можете вручную добавлять таблицы вFROMусловие SQL с помощьюtables.whereиtablesоба принимают список строк. Все параметрыwhere«И» с другими критериями поиска.Пример:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
… (приблизительно) переводится в следующий SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Будьте осторожны при использовании параметра
tables, если вы указываете таблицы, которые уже используются в запросе. Когда вы добавляете дополнительные таблицы с помощью параметраtables, Django предполагает, что вы хотите включить эту таблицу ещё раз, если она уже включена. Это создаёт проблему, так как имя таблицы будет присвоено псевдоним. Если таблица появляется несколько раз в операторе SQL, для второй и последующих появлений таблицы необходимо использовать псевдонимы, чтобы база данных могла их различать. Если вы ссылаетесь на дополнительную таблицу, добавленную в параметр дополнительного условияwhere, это приведёт к ошибкам.Обычно вы будете добавлять только дополнительные таблицы, которые ещё не присутствуют в запросе. Однако, если возникнет описанный выше случай, существуют несколько решений. Во-первых, попробуйте обойтись без включения дополнительной таблицы и использовать уже имеющуюся в запросе. Если это невозможно, поместите вызов
extra()в начало построения набора запросов, чтобы ваша таблица была первым использованием этой таблицы. Наконец, если ничего не поможет, посмотрите на сгенерированный запрос и перепишите добавлениеwhereтаким образом, чтобы использовать псевдоним, назначенный вашей дополнительной таблице. Псевдоним будет одинаковым каждый раз, когда вы будете создавать набор запросов таким же образом, поэтому вы можете полагаться на имя псевдонима, чтобы оно не менялось. -
order_byЕсли вам нужно отсортировать результирующий набор запросов, используя некоторые из новых полей или таблиц, добавленных вами с помощью
extra(), используйте параметрorder_byдляextra()и передайте последовательность строк. Эти строки должны быть либо полями модели (как в обычном методеorder_by()для наборов запросов), либо в форматеtable_name.column_name, либо псевдонимом столбца, указанного в параметреselectдляextra().Например:
q = Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"}) q = q.extra(order_by=["-is_recent"])Это отсортирует все элементы, для которых
is_recentистинно, в начало результата (Trueсортируется передFalseв порядке убывания).Кстати, это показывает, что вы можете выполнять несколько вызовов
extra(), и он будет работать так, как вы ожидаете (каждый раз добавляя новые ограничения). -
paramsВ параметре
where, описанном выше, можно использовать стандартные плейсхолдеры Python для строк баз данных —'%s', чтобы указать параметры, которые база данных должна автоматически заключить в кавычки. Параметрparams— это список дополнительных параметров, которые нужно заменить.Пример:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Всегда используйте
paramsвместо прямого встраивания значений вwhere, потому чтоparamsгарантирует, что значения будут заключены в кавычки в соответствии с вашей конкретной базой данных. Например, кавычки будут экранированы правильно.Плохо:
Entry.objects.extra(where=["headline='Lennon'"])
Хорошо:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Предупреждение
Если вы выполняете запросы в MySQL, обратите внимание, что неявное приведение типов в MySQL может привести к неожиданным результатам при смешивании типов. Если вы выполняете запрос на строковый столбец, но с целым числом, MySQL приведет типы всех значений в таблице к целому числу перед выполнением сравнения. Например, если ваша таблица содержит значения 'abc', 'def', и вы выполняете запрос на WHERE mycolumn=0, обе строки будут совпадать. Чтобы предотвратить это, выполните правильное приведение типов перед использованием значения в запросе.
defer()
-
defer(*fields)
В некоторых сложных ситуациях моделирования данных ваши модели могут содержать много полей, некоторые из которых могут содержать много данных (например, текстовые поля) или требуют дорогостоящей обработки для преобразования в объекты Python. Если вы используете результаты набора запросов в какой-то ситуации, где вы не знаете, нужны ли вам эти конкретные поля, когда вы изначально получаете данные, вы можете указать Django не загружать их из базы данных.
Это делается путём передачи имён полей, которые не нужно загружать, в defer():
Entry.objects.defer("headline", "body")
Набор запросов с отложенными полями всё ещё вернёт экземпляры модели. Каждое отложенное поле будет извлечено из базы данных, если вы обратитесь к этому полю (по одному, не все отложенные поля сразу).
Примечание
Отложенные поля не будут загружаться лениво из асинхронного кода. Вместо этого вы получите исключение SynchronousOnlyOperation. Если вы пишете асинхронный код, вам не следует пытаться получить доступ к любым полям, которые вы defer().
Вы можете сделать несколько вызовов defer(). Каждый вызов добавляет новые поля в отложенный набор:
# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")
Порядок, в котором поля добавляются в отложенный набор, не имеет значения. Вызов defer() с именем поля, которое уже было отложено, безопасен (поле всё равно будет отложено).
Вы можете отложить загрузку полей в связанных моделях (если связанные модели загружаются через select_related()) с помощью стандартной нотации двойного подчёркивания для разделения связанных полей:
Blog.objects.select_related().defer("entry__headline", "entry__body")
Если вы хотите очистить набор отложенных полей, передайте None в качестве параметра к defer():
# Load all fields immediately. my_queryset.defer(None)
Некоторые поля в модели не будут отложены, даже если вы их запросите. Вы никогда не можете отложить загрузку первичного ключа. Если вы используете select_related() для получения связанных моделей, вам не следует откладывать загрузку поля, которое связывает первичную модель со связанной, в противном случае это приведёт к ошибке.
Аналогично, вызов defer() (или его аналог only()) включая аргумент из агрегации (например, используя результат annotate()) не имеет смысла: это приведёт к исключению. Агрегированные значения всегда будут извлечены в результирующий набор запросов.
Примечание
Метод defer() (и его кузен only(), ниже) предназначены только для продвинутых случаев. Они обеспечивают оптимизацию, когда вы тщательно проанализировали свои запросы и понимаете точно, какая информация вам нужна, и измерили, что разница между возвратом необходимых полей и полным набором полей для модели будет значительной.
Даже если вы считаете, что находитесь в ситуации продвинутого случая, используйте только defer() когда вы не можете на этапе загрузки набора запросов определить, нужны ли вам дополнительные поля или нет. Если вы часто загружаете и используете определённый поднабор данных, лучшим выбором будет нормализовать ваши модели и поместить не загруженные данные в отдельную модель (и таблицу базы данных). Если столбцы должны остаться в одной таблице по какой-либо причине, создайте модель с Meta.managed = False (см. managed attribute документацию), содержащую только поля, которые вам обычно нужно загрузить и использовать, где вы могли бы иначе вызвать defer(). Это делает ваш код более ясным для читателя, немного быстрее и потребляет немного меньше памяти в процессе Python.
Например, обе эти модели используют одну и ту же базу данных:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = "app_largetable"
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = "app_largetable"
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer("f2")
Если многие поля должны быть дублированы в необработанной модели, лучше всего создать абстрактную модель со общими полями, а затем заставить необработанные и обработанные модели наследоваться от абстрактной модели.
Примечание
При вызове save() для экземпляров с отложенными полями, будут сохранены только загруженные поля. См. save() для получения дополнительной информации.
only()
-
only(*fields)
Метод only() по сути является противоположностью defer(). Только поля, переданные в этот метод и которые не уже указаны как отложенные, загружаются немедленно при оценке набора запросов.
Если у вас есть модель, где почти все поля необходимо отложить, использование only() для указания дополнительного набора полей может привести к более простому коду.
Предположим, у вас есть модель с полями name, age и biography. Следующие два набора запросов одинаковы в плане отложенных полей:
Person.objects.defer("age", "biography")
Person.objects.only("name")
Всякий раз, когда вы вызываете only(), он заменяет набор полей для немедленной загрузки. Имя метода является мнемоническим: только эти поля загружаются немедленно; остальные откладываются. Таким образом, последовательные вызовы only() приводят к тому, что только окончательные поля учитываются:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
Поскольку defer() действует пошагово (добавляя поля в список отложенных), вы можете объединить вызовы only() и defer() и вещи будут вести себя логично:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline immediately.
Entry.objects.defer("body").only("headline", "body")
Все предупреждения в примечании для документации defer() также применимы к only(). Используйте его осторожно и только после того, как исчерпаете все другие варианты.
Использование only() и пропуск поля, запрошенного с помощью select_related(), является ошибкой. С другой стороны, вызов only() без аргументов вернёт все поля (включая аннотации), извлечённые набором запросов.
Как и с defer(), вы не можете получить доступ к не загруженным полям из асинхронного кода и ожидать их загрузки. Вместо этого вы получите исключение SynchronousOnlyOperation. Убедитесь, что все поля, к которым вы можете получить доступ, находятся в вашем вызове only().
Примечание
При вызове save() для экземпляров с отложенными полями, будут сохранены только загруженные поля. См. save() для получения дополнительной информации.
Примечание
При использовании defer() после only() поля в defer() переопределят only() для полей, которые перечислены в обоих.
using()
-
using(alias)
Этот метод предназначен для управления базой данных, по отношению к которой будет вычисляться QuerySet если вы используете более одной базы данных. Единственным аргументом этого метода является псевдоним базы данных, как определено в DATABASES.
Например:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using("backup")
select_for_update()
-
select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)
Возвращает набор запросов, который заблокирует строки до конца транзакции, генерируя инструкцию SQL SELECT ... FOR UPDATE на поддерживаемых базах данных.
Например:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
При оценке набора запросов (for entry in entries в данном случае), все соответствующие записи будут заблокированы до конца блока транзакции, что означает, что другие транзакции не смогут изменять или получать блокировки на них.
Обычно, если другая транзакция уже получила блокировку на одной из выбранных строк, запрос будет блокироваться до тех пор, пока блокировка не будет освобождена. Если это не то поведение, которое вы хотите, вызовите select_for_update(nowait=True). Это сделает вызов неблокирующим. Если блокировка конфликта уже получена другой транзакцией, DatabaseError будет поднято при оценке набора запросов. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True) вместо этого. nowait и skip_locked взаимно исключают друг друга, и попытки вызвать select_for_update() с обоими включёнными вариантами приведут к ValueError.
По умолчанию select_for_update() блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанных в select_related(), заблокированы в дополнение к строкам модели набора запросов. Если этого не требуется, укажите связанные объекты, которые вы хотите заблокировать в select_for_update(of=(...)) с использованием того же синтаксиса полей, что и в select_related(). Используйте значение 'self' для ссылки на модель набора запросов.
Блокировка родительских моделей в select_for_update(of=(...))
Если вы хотите заблокировать родительские модели при использовании наследования по нескольким таблицам, вы должны указать поля связи родительских объектов (по умолчанию <parent_model_name>_ptr) в аргументе of. Например:
Restaurant.objects.select_for_update(of=("self", "place_ptr"))
Использование select_for_update(of=(...)) со специфицированными полями
Если вы хотите заблокировать модели и указать выбранные поля, например, используя values(), вы должны выбрать как минимум одно поле из каждой модели в аргументе of. Модели без выбранных полей не будут заблокированы.
Только для PostgreSQL вы можете передать no_key=True для получения более слабой блокировки, которая всё ещё позволяет создавать строки, которые просто ссылаются на заблокированные строки (например, через внешний ключ), пока блокировка активна. Дополнительные сведения о режимах блокировки строк см. в документации PostgreSQL: row-level lock modes.
Вы не можете использовать 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
Чтобы избежать этого ограничения, вы можете исключить нулевые объекты, если вам они не нужны:
>>> Person.objects.select_related("hometown").select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
Базовые блоки postgresql, oracle, и mysql базы данных поддерживают select_for_update(). Однако MariaDB поддерживает только аргумент nowait, MariaDB 10.6+ также поддерживает аргумент skip_locked, а MySQL поддерживает аргументы nowait, skip_locked, и of. Аргумент no_key поддерживается только в PostgreSQL.
Передача nowait=True, skip_locked=True, no_key=True, или of в select_for_update() с помощью баз данных, которые не поддерживают эти параметры, например, MySQL, вызывает NotSupportedError. Это предотвращает непредвиденное блокирование кода.
Оценивание набора запросов с select_for_update() в режиме autocommit на серверах, которые поддерживают SELECT ... FOR UPDATE, является ошибкой TransactionManagementError, так как в этом случае строки не блокируются. Если это разрешено, это может привести к искажению данных и может быть легко вызвано кодом, который ожидает выполнения вне транзакции.
Использование select_for_update() на серверах, которые не поддерживают SELECT ... FOR UPDATE (например, SQLite), не оказывает никакого влияния. SELECT ... FOR UPDATE не будет добавлен в запрос, и ошибка не возникает, если select_for_update() используется в режиме autocommit.
Предупреждение
Хотя select_for_update() обычно завершается ошибкой в режиме 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.
Операторы, возвращающие новые QuerySet
Объединённые наборы запросов должны использовать одну и ту же модель.
И (&)
Комбинирует два QuerySet с помощью оператора SQL AND аналогично цепочке фильтров.
Следующее эквивалентно:
Model.objects.filter(x=1) & Model.objects.filter(y=2) Model.objects.filter(x=1).filter(y=2)
Эквивалент SQL:
SELECT ... WHERE x=1 AND y=2
ИЛИ (|)
Комбинирует два QuerySet с помощью оператора SQL OR.
Следующее эквивалентно:
Model.objects.filter(x=1) | Model.objects.filter(y=2) from django.db.models import Q Model.objects.filter(Q(x=1) | Q(y=2))
Эквивалент SQL:
SELECT ... WHERE x=1 OR y=2
| не является коммутативной операцией, так как могут быть сгенерированы различные (хотя и эквивалентные) запросы.
ИСКЛЮЧАЮЩЕЕ ИЛИ (^)
Комбинирует два QuerySet с помощью оператора SQL XOR . Выражение XOR соответствует строкам, которые соответствуют нечётному количеству операндов.
Следующее эквивалентно:
Model.objects.filter(x=1) ^ Model.objects.filter(y=2) from django.db.models import Q Model.objects.filter(Q(x=1) ^ Q(y=2))
Эквивалент SQL:
SELECT ... WHERE x=1 XOR y=2
Примечание
XOR напрямую поддерживается в MariaDB и MySQL. В других базах данных x ^ y ^ ... ^ z преобразуется в эквивалент:
(x OR y OR ... OR z) AND
1=MOD(
(CASE WHEN x THEN 1 ELSE 0 END) +
(CASE WHEN y THEN 1 ELSE 0 END) +
...
(CASE WHEN z THEN 1 ELSE 0 END),
2
)
В более старых версиях в базах данных без родной поддержки оператора SQL XOR XOR возвращало строки, которые соответствовали ровно одному операнду. Предыдущее поведение не соответствовало поведению MySQL, MariaDB и Python.
Методы, которые не возвращают QuerySet
Следующие методы QuerySet оценивают QuerySet и возвращают не QuerySet.
Эти методы не используют кэш (см. Кэширование и QuerySet). Вместо этого они каждый раз обращаются к базе данных.
Поскольку эти методы оценивают QuerySet, они являются блокирующими вызовами, и поэтому их основные (синхронные) версии нельзя вызывать из асинхронного кода. По этой причине у каждого есть соответствующий асинхронный аналог с префиксом a - например, вместо get(…) вы можете использовать await aget(…).
Обычно поведение отличается только асинхронностью, но любые различия указаны ниже рядом с каждым методом.
get()
-
get(*args, **kwargs)
-
aget(*args, **kwargs)
Асинхронная версия: aget()
Возвращает объект, соответствующий заданным параметрам поиска, которые должны быть в формате, описанном в Поиск по полям. Вы должны использовать уникальные поиски, такие как первичный ключ или поля в уникальном ограничении. Например:
Entry.objects.get(id=1) Entry.objects.get(Q(blog=blog) & Q(entry_number=1))
Если вы ожидаете, что набор запросов уже вернёт одну строку, вы можете использовать get() без аргументов, чтобы вернуть объект для этой строки:
Entry.objects.filter(pk=1).get()
Если get() не найдёт ни одного объекта, он вызывает исключение Model.DoesNotExist:
Entry.objects.get(id=-999) # raises Entry.DoesNotExist
Если get() найдёт более одного объекта, он вызывает исключение Model.MultipleObjectsReturned:
Entry.objects.get(name="A Duplicated Name") # raises Entry.MultipleObjectsReturned
Оба этих класса исключений являются атрибутами класса модели и специфичны для этой модели. Если вы хотите обрабатывать такие исключения для нескольких вызовов get() для разных моделей, вы можете использовать их обобщённые базовые классы. Например, вы можете использовать django.core.exceptions.ObjectDoesNotExist для обработки исключений DoesNotExist из нескольких моделей:
from django.core.exceptions import ObjectDoesNotExist
try:
blog = Blog.objects.get(id=1)
entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
print("Either the blog or entry doesn't exist.")
create()
-
create(**kwargs)
-
acreate(**kwargs)
Асинхронная версия: acreate()
Удобный метод для создания объекта и его сохранения в одном шаге. Таким образом:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
и:
p = Person(first_name="Bruce", last_name="Springsteen") p.save(force_insert=True)
эквивалентны.
Параметр force_insert документирован в другом месте, но всё, что он означает, это то, что новый объект всегда будет создан. Обычно об этом не нужно беспокоиться. Однако если ваша модель содержит явное значение первичного ключа, которое вы устанавливаете, и если это значение уже существует в базе данных, вызов create() завершится ошибкой IntegrityError, так как первичные ключи должны быть уникальными. Будьте готовы обработать исключение, если вы используете явные первичные ключи.
get_or_create()
-
get_or_create(defaults=None, **kwargs)
-
aget_or_create(defaults=None, **kwargs)
Асинхронная версия: aget_or_create()
Удобный метод для поиска объекта с заданными kwargs (может быть пустым, если в вашей модели есть значения по умолчанию для всех полей), создавая его при необходимости.
Возвращает кортеж из (object, created), где object — полученный или созданный объект, а created — булево значение, указывающее, был ли создан новый объект.
Это предназначено для предотвращения дублирования объектов при одновременных запросах и как сокращение громоздкого кода. Например:
try:
obj = Person.objects.get(first_name="John", last_name="Lennon")
except Person.DoesNotExist:
obj = Person(first_name="John", last_name="Lennon", birthday=date(1940, 10, 9))
obj.save()
Здесь, при одновременных запросах, могут быть предприняты несколько попыток сохранения Person с одинаковыми параметрами. Чтобы избежать этой гонки, вышеприведенный пример можно переписать, используя get_or_create() следующим образом:
obj, created = Person.objects.get_or_create(
first_name="John",
last_name="Lennon",
defaults={"birthday": date(1940, 10, 9)},
)
Все ключевые аргументы, передаваемые в get_or_create() — за исключением необязательного аргумента с именем defaults — будут использованы в вызове get(). Если объект найден, get_or_create() возвращает кортеж из этого объекта и False.
Предупреждение
Этот метод является атомарным, предполагая, что база данных обеспечивает уникальность ключевых аргументов (см. unique или unique_together). Если поля, используемые в ключевых аргументах, не имеют ограничения уникальности, одновременные вызовы этого метода могут привести к вставке нескольких строк с одинаковыми параметрами.
Вы можете указать более сложные условия для полученного объекта, объединив get_or_create() с filter() и используя Q objects. Например, для получения Роберта или Боба Марли, если любой из них существует, и создания последнего в противном случае:
from django.db.models import Q
obj, created = Person.objects.filter(
Q(first_name="Bob") | Q(first_name="Robert"),
).get_or_create(last_name="Marley", defaults={"first_name": "Bob"})
Если найдено несколько объектов, get_or_create() вызывает исключение MultipleObjectsReturned. Если объект не найден, get_or_create() создаст и сохранит новый объект, вернув кортеж из нового объекта и True. Новый объект будет создан примерно по следующему алгоритму:
params = {k: v for k, v in kwargs.items() if "__" not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
Это означает, что начните с любого не-'defaults' ключевого аргумента, который не содержит двойного подчеркивания (что указывает на неточные условия поиска). Затем добавьте содержимое defaults, перезаписывая необходимые ключи, и используйте результат в качестве ключевых аргументов для класса модели. Если в defaults есть какие-либо вызываемые функции, вычислите их. Как намекалось выше, это упрощенное описание алгоритма, используемого, но оно содержит все необходимые подробности. Внутренняя реализация имеет больше проверок ошибок, чем это, и обрабатывает некоторые дополнительные краевые случаи; если вас интересует подробность, прочитайте код.
Если у вас есть поле с именем defaults и вы хотите использовать его как точное условие поиска в get_or_create(), используйте 'defaults__exact', как показано ниже:
Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})
Метод get_or_create() имеет поведение, аналогичное поведению create() при использовании вручную указанных первичных ключей. Если объект нужно создать, а ключ уже существует в базе данных, будет вызвано исключение IntegrityError.
Наконец, несколько слов об использовании get_or_create() в представлениях Django. Пожалуйста, используйте его только в POST запросах, если у вас нет веской причины этого не делать. GET запросы не должны влиять на данные. Вместо этого используйте POST всякий раз, когда запрос на страницу оказывает побочное действие на ваши данные. Дополнительную информацию см. в Безопасные методы в спецификации HTTP.
Предупреждение
Вы можете использовать get_or_create() через атрибуты ManyToManyField и обратные связи. В этом случае вы ограничите запросы в контексте этой связи. Это может привести к проблемам целостности, если вы не используете его последовательно.
Пусть будут следующие модели:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
Вы можете использовать get_or_create() через поле глав в книге, но оно извлекает данные только в контексте этой книги:
>>> book = Book.objects.create(title="Ulysses") >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, True) >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, False) >>> Chapter.objects.create(title="Chapter 1") <Chapter: Chapter 1> >>> book.chapters.get_or_create(title="Chapter 1") # Raises IntegrityError
Это происходит потому, что он пытается получить или создать «Главу 1» через книгу «Улисс», но не может сделать ни того, ни другого: отношение не может извлечь эту главу, потому что она не связана с этой книгой, и не может создать ее, так как поле title должно быть уникальным.
update_or_create()
-
update_or_create(defaults=None, create_defaults=None, **kwargs)
-
aupdate_or_create(defaults=None, create_defaults=None, **kwargs)
Асинхронная версия: aupdate_or_create()
Удобный метод для обновления объекта с заданными kwargs, создавая новый, если необходимо. И create_defaults и defaults — это словари пар (поле, значение). Значения в create_defaults и defaults могут быть вызываемыми функциями. defaults используется для обновления объекта, а create_defaults — для создания. Если create_defaults не указано, defaults будет использоваться для создания.
Возвращает кортеж из (object, created), где object — созданный или обновленный объект, а created — булево значение, указывающее, был ли создан новый объект.
Метод update_or_create пытается извлечь объект из базы данных на основе заданных kwargs. Если совпадение найдено, он обновляет поля, переданные в словаре defaults.
Это сокращение громоздкого кода. Например:
defaults = {"first_name": "Bob"}
create_defaults = {"first_name": "Bob", "birthday": date(1940, 10, 9)}
try:
obj = Person.objects.get(first_name="John", last_name="Lennon")
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {"first_name": "John", "last_name": "Lennon"}
new_values.update(create_defaults)
obj = Person(**new_values)
obj.save()
Этот шаблон становится громоздким по мере увеличения количества полей в модели. Вышеупомянутый пример можно переписать с помощью update_or_create() следующим образом:
obj, created = Person.objects.update_or_create(
first_name="John",
last_name="Lennon",
defaults={"first_name": "Bob"},
create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)
Подробное описание того, как разрешаются имена, переданные в kwargs, см. в get_or_create().
Как описано выше в get_or_create(), этот метод подвержен гонке, которая может привести к одновременной вставке нескольких строк, если уникальность не обеспечивается на уровне базы данных.
Как и get_or_create() и create(), если вы используете вручную указанные первичные ключи и объект необходимо создать, но ключ уже существует в базе данных, будет вызвано исключение IntegrityError.
В более ранних версиях update_or_create() не указывал update_fields при вызове Model.save().
Был добавлен аргумент create_defaults.
bulk_create()
-
bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
-
abulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
Асинхронная версия: abulk_create()
Этот метод вставляет предоставленный список объектов в базу данных эффективно (обычно всего 1 запрос, независимо от количества объектов) и возвращает созданные объекты в виде списка в том же порядке, что и предоставленный:
>>> objs = Entry.objects.bulk_create( ... [ ... Entry(headline="This is a test"), ... Entry(headline="This is only a test"), ... ] ... )
Однако есть ряд ограничений:
- Метод модели
save()не будет вызываться, и сигналыpre_saveиpost_saveне будут отправлены. - Он не работает с дочерними моделями в сценарии наследования с несколькими таблицами.
- Если первичный ключ модели является
AutoFieldиignore_conflictsравно False, атрибут первичного ключа может быть получен только на определенных базах данных (в настоящее время PostgreSQL, MariaDB 10.5+ и SQLite 3.35+). На других базах данных он не будет установлен. - Он не работает с многозначными отношениями.
-
Он преобразует
objsв список, что полностью вычисляетobjs, если это генератор. Преобразование в список позволяет инспектировать все объекты, чтобы любые объекты с вручную установленным первичным ключом можно было вставить первыми. Если вы хотите вставлять объекты партиями, не вычисляя весь генератор сразу, вы можете использовать эту технику, пока объекты не имеют вручную установленных первичных ключей:from itertools import islice batch_size = 100 objs = (Entry(headline="Test %s" % i) for i in range(1000)) while True: batch = list(islice(objs, batch_size)) if not batch: break Entry.objects.bulk_create(batch, batch_size)
Параметр batch_size контролирует количество объектов, создаваемых в одном запросе. Значение по умолчанию — создание всех объектов в одной партии, за исключением SQLite, где значение по умолчанию таково, что используется не более 999 переменных на запрос.
На базах данных, которые это поддерживают (все, кроме Oracle), установка параметра ignore_conflicts в True указывает базе данных игнорировать ошибки при вставке строк, которые нарушают ограничения, такие как дублирование уникальных значений.
В базах данных, которые это поддерживают (все, кроме Oracle), установка параметра update_conflicts в значение True сообщает базе данных об обновлении update_fields при сбое вставки строки из-за конфликтов. В PostgreSQL и SQLite, помимо update_fields, необходимо указать список unique_fields, которые могут быть в конфликте.
Включение параметра ignore_conflicts отключает установку первичного ключа на каждом экземпляре модели (если база данных это обычно поддерживает).
В более ранних версиях включение параметра update_conflicts предотвращало установку первичного ключа на каждом экземпляре модели.
Предупреждение
В MySQL и MariaDB установка параметра ignore_conflicts в значение True преобразует определенные типы ошибок, помимо ошибок дублирования ключа, в предупреждения. Даже в режиме Strict Mode. Например: недействительные значения или нарушения неявной обязательности. См. документацию MySQL по режиму SQL и документацию MariaDB по исключению для получения более подробной информации.
bulk_update()
-
bulk_update(objs, fields, batch_size=None)
-
abulk_update(objs, fields, batch_size=None)
Асинхронная версия: abulk_update()
Этот метод эффективно обновляет указанные поля в предоставленных экземплярах модели, обычно одной запросом, и возвращает количество обновленных объектов:
>>> objs = [ ... Entry.objects.create(headline="Entry 1"), ... Entry.objects.create(headline="Entry 2"), ... ] >>> objs[0].headline = "This is entry 1" >>> objs[1].headline = "This is entry 2" >>> Entry.objects.bulk_update(objs, ["headline"]) 2
QuerySet.update() используется для сохранения изменений, поэтому это более эффективно, чем итерирование по списку моделей и вызов save() для каждой из них, но у него есть несколько нюансов:
- Вы не можете обновить первичный ключ модели.
- Метод
save()каждой модели не вызывается, и сигналыpre_saveиpost_saveне отправляются. - Если обновляется большое количество столбцов в большом количестве строк, генерируемый SQL-запрос может быть очень большим. Избегайте этого, указав подходящий
batch_size. - Обновление полей, определенных в предках многотабличного наследования, потребует дополнительного запроса на каждый предок.
- Если в отдельной партии есть дубликаты, только первый экземпляр в этой партии приведет к обновлению.
- Количество обновленных объектов, возвращаемое функцией, может быть меньше количества переданных объектов. Это может быть вызвано передачей дублирующих объектов в одной партии или конкурентными условиями, из-за которых объекты больше не присутствуют в базе данных.
Параметр batch_size управляет количеством объектов, сохраняемых в одном запросе. По умолчанию все объекты обновляются в одной партии, за исключением SQLite и Oracle, у которых есть ограничения на количество переменных, используемых в запросе.
count()
-
count()
-
acount()
Асинхронная версия: acount()
Возвращает целое число, представляющее количество объектов в базе данных, соответствующих QuerySet.
Пример:
# Returns the total number of entries in the database. Entry.objects.count() # Returns the number of entries whose headline contains 'Lennon' Entry.objects.filter(headline__contains="Lennon").count()
Вызов count() выполняет SELECT COUNT(*) в фоновом режиме, поэтому вы всегда должны использовать count() вместо загрузки всех записей в объекты Python и вызова len() на результате (если вам не нужно загружать объекты в память, в противном случае len() будет быстрее).
Обратите внимание, что если вы хотите получить количество элементов в QuerySet и также извлекать экземпляры модели из него (например, итерируя по нему), вероятно, более эффективно использовать len(queryset), который не вызовет дополнительный запрос к базе данных, в отличие от count().
Если набор запросов уже полностью получен, count() будет использовать эту длину, а не выполнять дополнительный запрос к базе данных.
in_bulk()
-
in_bulk(id_list=None, *, field_name='pk')
-
ain_bulk(id_list=None, *, field_name='pk')
Асинхронная версия: ain_bulk()
Принимает список значений поля (id_list) и field_name для этих значений и возвращает словарь, сопоставляющий каждое значение с экземпляром объекта с заданным значением поля. Исключение django.core.exceptions.ObjectDoesNotExist никогда не будет вызвано in_bulk; то есть любое значение id_list не соответствующее ни одному экземпляру, просто игнорируется. Если id_list не указано, возвращаются все объекты в наборе запросов. field_name должно быть уникальным полем или отдельным полем (если в distinct() указано только одно поле). field_name по умолчанию является первичным ключом.
Пример:
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(["beatles_blog"], field_name="slug")
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct("name").in_bulk(field_name="name")
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}
Если вы передадите in_bulk() пустой список, вы получите пустой словарь.
iterator()
-
iterator(chunk_size=None)
-
aiterator(chunk_size=None)
Асинхронная версия: aiterator()
Вычисляет QuerySet (выполняя запрос) и возвращает итератор (см. PEP 234) по результатам или асинхронный итератор (см. PEP 492), если вы вызываете его асинхронную версию aiterator.
Набор запросов обычно кеширует свои результаты, чтобы повторные оценки не приводили к дополнительным запросам. В отличие от этого, iterator() будет считывать результаты напрямую, не выполняя никакого кеширования на уровне QuerySet (внутренне, итератор по умолчанию вызывает iterator() и кеширует возвращаемое значение). Для QuerySet который возвращает большое количество объектов, к которым вам нужно получить доступ только один раз, это может привести к лучшей производительности и значительному сокращению потребления памяти.
Обратите внимание, что использование iterator() на наборе запросов, который уже был вычислен, заставит его перевычислиться, повторив запрос.
iterator() совместим с предыдущими вызовами prefetch_related() при условии, что chunk_size задан. Более большие значения потребуют меньше запросов для выполнения предварительной выборки с затратами на увеличение использования памяти.
Добавлена поддержка aiterator() с предыдущими вызовами prefetch_related().
В некоторых базах данных (например, Oracle, SQLite) может быть ограничено максимальное количество терминов в SQL-запросе IN условия. Следовательно, следует использовать значения ниже этого предела. (В частности, когда выполняется предварительная выборка по двум или более отношениям, chunk_size должен быть достаточно мал, чтобы ожидаемое количество результатов для каждого предварительно выбранного отношения все еще оставалось ниже предела.)
Пока набор запросов не предварительно выбирает какие-либо связанные объекты, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявный стандартный параметр 2000.
В зависимости от базы данных, результаты запроса будут загружаться все сразу или передаваться из базы данных с помощью курсоров на стороне сервера.
С курсорами на стороне сервера
Oracle и PostgreSQL используют курсоры на стороне сервера для передачи результатов из базы данных без загрузки всего набора результатов в память.
Драйвер базы данных Oracle всегда использует курсоры на стороне сервера.
С курсорами на стороне сервера параметр chunk_size задает количество результатов, которые будут кэшированы на уровне драйвера базы данных. Загрузка больших блоков уменьшает количество циклов между драйвером базы данных и базой данных, но приводит к большему потреблению памяти.
В PostgreSQL курсоры на стороне сервера будут использоваться только тогда, когда значение параметра DISABLE_SERVER_SIDE_CURSORS равно False. Читайте Пулы транзакций и курсоры на стороне сервера, если вы используете компоновщик подключений, настроенный в режиме пула транзакций. Когда курсоры на стороне сервера отключены, поведение становится таким же, как в базах данных, которые не поддерживают курсоры на стороне сервера.
Без курсоров на стороне сервера
MySQL не поддерживает передачу результатов, поэтому драйвер базы данных Python загружает весь набор результатов в память. Затем набор результатов преобразуется в объекты строк Python адаптером базы данных с использованием метода fetchmany() определенного в PEP 249.
SQLite может извлекать результаты по частям с помощью fetchmany(), но поскольку SQLite не предоставляет изоляции между запросами в рамках одного подключения, будьте осторожны при записи в таблицу, по которой выполняется итерация. См. Изоляция при использовании QuerySet.iterator() для получения дополнительной информации.
Параметр chunk_size управляет размером пакетов, которые Django извлекает из драйвера базы данных. Более крупные пакеты уменьшают нагрузку на взаимодействие с драйвером базы данных, но незначительно увеличивают потребление памяти.
До тех пор, пока QuerySet не предварительно загружает связанные объекты, отсутствие значения для chunk_size приведет к использованию Django неявного значения по умолчанию 2000, выведенного из расчета на почтовой рассылке psycopg:
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 нет определённой сортировки, то 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(), но возвращает последний объект в QuerySet.
aggregate()
-
aggregate(*args, **kwargs)
-
aaggregate(*args, **kwargs)
Асинхронный вариант: aaggregate()
Возвращает словарь агрегированных значений (средних, сумм и т. д.) вычисленных по QuerySet. Каждый аргумент в aggregate() указывает значение, которое будет включено в возвращаемый словарь.
Функции агрегирования, предоставляемые Django, описаны в Функции агрегирования ниже. Поскольку агрегаты также являются выражениями запроса, можно комбинировать агрегаты с другими агрегатами или значениями для создания сложных агрегатов.
Агрегаты, указанные с использованием ключевых аргументов, будут использовать ключевое слово в качестве имени аннотации. Анонимные аргументы будут иметь имя, сгенерированное на основе имени функции агрегирования и поля модели, которое агрегируется. Сложные агрегаты не могут использовать анонимные аргументы и должны указать ключевой аргумент в качестве псевдонима.
Например, при работе со статьями блога, вы можете захотеть узнать количество авторов, которые внесли вклад в статьи блога:
>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry"))
{'entry__count': 16}
Используя ключевой аргумент для указания функции агрегирования, вы можете управлять именем возвращаемого агрегированного значения:
>>> Blog.objects.aggregate(number_of_entries=Count("entry"))
{'number_of_entries': 16}
Для углублённого обсуждения агрегирования см. Руководство по теме агрегирования.
exists()
-
exists()
-
aexists()
Асинхронный вариант: aexists()
Возвращает True если QuerySet содержит результаты, и False в противном случае. Эта функция пытается выполнить запрос самым простым и быстрым способом, но она выполняет почти такой же запрос, как и обычный запрос QuerySet.
exists() полезна для поиска, связанного с существованием каких-либо объектов в QuerySet, особенно в контексте большого QuerySet.
Для проверки, содержит ли 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")
… но не на много (поэтому для получения эффективности нужно большое количество QuerySet).
Кроме того, если QuerySet ещё не был обработан, но вы знаете, что он будет обработан в какой-то момент, то использование some_queryset.exists() потребует больше работы (один запрос для проверки существования и дополнительный запрос для получения результатов), чем использование bool(some_queryset), которое получает результаты и затем проверяет, возвращены ли какие-либо результаты.
contains()
-
contains(obj)
-
acontains(obj)
Асинхронный вариант: acontains()
Возвращает True если QuerySet содержит obj, и False в противном случае. Эта функция пытается выполнить запрос самым простым и быстрым способом.
contains() полезна для проверки принадлежности объекта к QuerySet, особенно в контексте большого QuerySet.
Чтобы проверить, содержит ли QuerySet определенный элемент:
if some_queryset.contains(obj):
print("Entry contained in queryset")
Это будет быстрее, чем следующее, которое требует оценки и итерации по всему QuerySet:
if obj in some_queryset:
print("Entry contained in queryset")
Как и exists(), если some_queryset ещё не обработан, но вы знаете, что он будет обработан в какой-то момент, то использование some_queryset.contains(obj) сделает дополнительный запрос к базе данных, что, как правило, приводит к более медленной общей производительности.
update()
-
update(**kwargs)
-
aupdate(**kwargs)
Асинхронная версия: aupdate()
Выполняет SQL-запрос обновления для указанных полей и возвращает количество изменённых строк (которое может не совпадать с количеством обновлённых строк, если некоторые строки уже имеют новое значение).
Например, чтобы отключить комментарии для всех записей блога, опубликованных в 2010 году, можно сделать так:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(Предполагается, что у вашей Entry модели есть поля pub_date и comments_on.)
Вы можете обновлять несколько полей — ограничений по количеству нет. Например, здесь мы обновляем поля comments_on и headline:
>>> Entry.objects.filter(pub_date__year=2010).update( ... comments_on=False, headline="This is old" ... )
Метод update() применяется мгновенно, и единственное ограничение для обновляемого QuerySet заключается в том, что он может обновлять только столбцы в основной таблице модели, а не в связанных моделях. Например, вы не можете сделать так:
>>> Entry.objects.update(blog__name="foo") # Won't work!
Однако фильтрация по связанным полям всё ещё возможна:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
Нельзя вызвать update() для QuerySet, для которого была взята часть или который по иным причинам больше нельзя отфильтровать.
Метод update() возвращает количество изменённых строк:
>>> Entry.objects.filter(id=64).update(comments_on=True) 1 >>> Entry.objects.filter(slug="nonexistent-slug").update(comments_on=True) 0 >>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False) 132
Если вы просто обновляете запись и вам не нужно ничего делать с объектом модели, наиболее эффективным подходом является вызов update(), а не загрузка объекта модели в память. Например, вместо этого:
e = Entry.objects.get(id=10) e.comments_on = False e.save()
…сделайте так:
Entry.objects.filter(id=10).update(comments_on=False)
Использование update() также предотвращает состояние гонки, когда что-то может измениться в вашей базе данных в короткий промежуток времени между загрузкой объекта и вызовом save().
Наконец, обратите внимание, что update() выполняет обновление на уровне SQL и, следовательно, не вызывает никаких save() методов ваших моделей, а также не генерирует сигналы pre_save или post_save (которые являются следствием вызова Model.save()). Если вы хотите обновить множество записей для модели, у которой есть настраиваемый метод save(), проитерируйтесь по ним и вызовите save(), как показано ниже:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
Упорядоченный набор результатов запроса
Цепной вызов order_by() с update() поддерживается только в MariaDB и MySQL и игнорируется для других баз данных. Это полезно для обновления уникального поля в указанном порядке без конфликтов. Например:
Entry.objects.order_by("-number").update(number=F("number") + 1)
Примечание
Оператор order_by() будет проигнорирован, если он содержит аннотации, унаследованные поля или запросы, охватывающие связи.
Удаление
-
delete()
-
adelete()
Асинхронная версия: adelete()
Выполняет SQL-запрос удаления всех строк в QuerySet и возвращает количество удалённых объектов и словарь с количеством удалений по каждому типу объектов.
delete() применяется мгновенно. Нельзя вызвать delete() для QuerySet, для которого была взята часть или который по иным причинам больше нельзя отфильтровать.
Например, чтобы удалить все записи в определённом блоге:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})
По умолчанию ForeignKey Django имитирует SQL-ограничение ON DELETE CASCADE — другими словами, все объекты со ссылками на удаляемые объекты будут удалены вместе с ними. Например:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})
Это поведение каскадирования можно настроить с помощью аргумента on_delete для ForeignKey.
Метод delete() выполняет массовое удаление и не вызывает никаких delete() методов ваших моделей. Однако он генерирует сигналы pre_delete и post_delete для всех удалённых объектов (включая каскадные удаления).
Django необходимо загрузить объекты в память, чтобы отправить сигналы и обработать каскады. Однако, если нет каскадов и нет сигналов, Django может использовать быстрый путь и удалять объекты без загрузки в память. Для больших удалений это может значительно уменьшить использование памяти. Кроме того, может быть уменьшено количество выполненных запросов.
ForeignKeys, установленные на on_delete DO_NOTHING не препятствуют использованию быстрого пути при удалении.
Обратите внимание, что запросы, генерируемые при удалении объектов, являются реализацией, которая может быть изменена.
В качестве менеджера
-
classmethod as_manager()
Метод класса, который возвращает экземпляр Manager с копией методов QuerySet. Дополнительные сведения см. в разделе Создание менеджера с методами QuerySet.
Обратите внимание, что в отличие от других пунктов этого раздела, у него нет асинхронной версии, так как он не выполняет запрос.
План выполнения запроса
-
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.
Field условия
Условия по полям — это способ указать суть SQL-оператор WHERE . Они указываются в качестве аргументов ключевых слов для методов QuerySet filter(), exclude() и get().
Для ознакомления см. документацию по моделям и базам данных.
Встроенные условия Django перечислены ниже. Также можно написать настраиваемые условия для полей модели.
Для удобства, когда тип условия не указан (как в Entry.objects.get(id=14)) тип условия предполагается exact.
exact
Точное совпадение. Если предоставленное значение для сравнения равно None, оно будет интерпретироваться как SQL-оператор NULL (см. isnull для получения более подробной информации).
Примеры:
Entry.objects.get(id__exact=14) Entry.objects.get(id__exact=None)
Эквиваленты в SQL:
SELECT ... WHERE id = 14; SELECT ... WHERE id IS NULL;
Сравнения MySQL
В MySQL, настройка «сортировки» таблицы базы данных определяет, являются ли сравнения exact чувствительными к регистру. Это настройка базы данных, а не Django. Можно настроить таблицы MySQL для использования сравнений, чувствительных к регистру, но это связано с некоторыми компромиссами. Дополнительную информацию об этом см. в разделе сортировка документации по базам данных.
iexact
Нечувствительное к регистру точное совпадение. Если предоставленное для сравнения значение None, оно будет интерпретировано как SQL NULL (см. isnull для получения более подробной информации).
Пример:
Blog.objects.get(name__iexact="beatles blog") Blog.objects.get(name__iexact=None)
Эквиваленты SQL:
SELECT ... WHERE name ILIKE 'beatles blog'; SELECT ... WHERE name IS NULL;
Обратите внимание, что первый запрос будет соответствовать 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG', и т.д.
Пользователи SQLite
При использовании бэкенда SQLite и строк, отличных от ASCII, имейте в виду примечание по базе данных о сравнениях строк. SQLite не выполняет нечувствительное к регистру сопоставление для строк, отличных от ASCII.
contains
Чувствительное к регистру проверка вхождения.
Пример:
Entry.objects.get(headline__contains="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline LIKE '%Lennon%';
Обратите внимание, что это будет соответствовать заголовку 'Lennon honored today' , но не 'lennon
honored today'.
Пользователи SQLite
SQLite не поддерживает чувствительные к регистру LIKE операторы; contains ведет себя как icontains для SQLite. См. примечание по базе данных для получения дополнительной информации.
icontains
Нечувствительное к регистру проверка вхождения.
Пример:
Entry.objects.get(headline__icontains="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline ILIKE '%Lennon%';
Пользователи SQLite
При использовании бэкенда SQLite и строк, отличных от ASCII, имейте в виду примечание по базе данных о сравнениях строк.
in
В заданном итерируемом объекте; часто список, кортеж или набор запросов. Это не распространенный случай использования, но строки (как итерируемые объекты) принимаются.
Примеры:
Entry.objects.filter(id__in=[1, 3, 4]) Entry.objects.filter(headline__in="abc")
Эквиваленты SQL:
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
Вы также можете использовать набор запросов для динамического вычисления списка значений вместо предоставления списка литеральных значений:
inner_qs = Blog.objects.filter(name__contains="Cheddar") entries = Entry.objects.filter(blog__in=inner_qs)
Этот набор запросов будет вычислен как подзапрос:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Если вы передаете QuerySet , полученный из values() или values_list(), в качестве значения для поиска __in, вам необходимо убедиться, что из результата извлекается только одно поле. Например, это сработает (фильтрация по названиям блогов):
inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Этот пример вызовет исключение, так как внутренний запрос пытается извлечь два значения поля, в то время как ожидается только одно:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Учет производительности
Будьте осторожны при использовании вложенных запросов и учитывайте характеристики производительности вашего сервера базы данных (в случае сомнений, проверьте!). Некоторые бэкэнды баз данных, в частности MySQL, не оптимизируют вложенные запросы очень хорошо. В таких случаях более эффективно извлечь список значений и затем передать его во второй запрос. То есть выполнить два запроса вместо одного:
values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Обратите внимание на list() вызов вокруг блогов QuerySet для принудительного выполнения первого запроса. Без него будет выполнен вложенный запрос, потому что наборы запросов ленивы.
gt
Больше чем.
Пример:
Entry.objects.filter(id__gt=4)
Эквивалент SQL:
SELECT ... WHERE id > 4;
gte
Больше или равно.
lt
Меньше чем.
lte
Меньше или равно.
startswith
Чувствительное к регистру начинается с.
Пример:
Entry.objects.filter(headline__startswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite не поддерживает чувствительные к регистру LIKE операторы; startswith ведет себя как istartswith для SQLite.
istartswith
Нечувствительное к регистру начинается с.
Пример:
Entry.objects.filter(headline__istartswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline ILIKE 'Lennon%';
Пользователи SQLite
При использовании бэкенда SQLite и строк, отличных от ASCII, имейте в виду примечание по базе данных о сравнениях строк.
endswith
Чувствительное к регистру заканчивается на.
Пример:
Entry.objects.filter(headline__endswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline LIKE '%Lennon';
Пользователи SQLite
SQLite не поддерживает чувствительные к регистру LIKE операторы; endswith ведет себя как iendswith для SQLite. См. документацию примечание по базе данных для получения дополнительной информации.
iendswith
Нечувствительное к регистру заканчивается на.
Пример:
Entry.objects.filter(headline__iendswith="Lennon")
Эквивалент SQL:
SELECT ... WHERE headline ILIKE '%Lennon'
Пользователи SQLite
При использовании бэкенда SQLite и строк, отличных от ASCII, имейте в виду примечание по базе данных о сравнениях строк.
range
Диапазон проверки (включительно).
Пример:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
Эквивалент SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Вы можете использовать range везде, где вы можете использовать BETWEEN в SQL — для дат, чисел и даже символов.
Предупреждение
Фильтрация DateTimeField с датами не будет включать элементы в последний день, потому что границы интерпретируются как «0:00 в заданную дату». Если pub_date был DateTimeField, вышеприведенное выражение будет преобразовано в следующий SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Как правило, вы не можете смешивать даты и datetime.
date
Для полей datetime значение преобразуется в дату. Позволяет цепочку дополнительных проверок полей. Принимает значение даты.
Пример:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(Для этого поиска не включен эквивалентный фрагмент кода SQL, так как реализация соответствующего запроса варьируется в зависимости от различных движков баз данных.)
Когда USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
year
Для полей date и datetime точное совпадение года. Позволяет цепочку дополнительных проверок полей. Принимает целое число - год.
Пример:
Entry.objects.filter(pub_date__year=2005) Entry.objects.filter(pub_date__year__gte=2005)
Эквивалент SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31'; SELECT ... WHERE pub_date >= '2005-01-01';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
iso_year
Для полей date и datetime точное совпадение года с учетом ISO 8601. Позволяет цепочку дополнительных проверок полей. Принимает целое число - год.
Пример:
Entry.objects.filter(pub_date__iso_year=2005) Entry.objects.filter(pub_date__iso_year__gte=2005)
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
month
Для полей date и datetime точное совпадение месяца. Позволяет цепочку дополнительных проверок полей. Принимает целое число от 1 (январь) до 12 (декабрь).
Пример:
Entry.objects.filter(pub_date__month=12) Entry.objects.filter(pub_date__month__gte=6)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
day
Для полей date и datetime точное совпадение дня. Позволяет цепочку дополнительных проверок полей. Принимает целое число - день.
Пример:
Entry.objects.filter(pub_date__day=3) Entry.objects.filter(pub_date__day__gte=3)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Обратите внимание, что это будет соответствовать любым записям с pub_date на третье число месяца, таким как 3 января, 3 июля и т. д.
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
week
Для полей даты и datetime возвращает номер недели (1-52 или 53) согласно ISO-8601, т. е. недели начинаются с понедельника, а первая неделя содержит первый четверг года.
Пример:
Entry.objects.filter(pub_date__week=52) Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(Для этого запроса не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса различается в разных баз данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
week_day
Для полей даты и datetime — соответствие дню недели. Позволяет цепочку дополнительных поисков по полям.
Принимает целое число, представляющее день недели от 1 (воскресенье) до 7 (суббота).
Пример:
Entry.objects.filter(pub_date__week_day=2) Entry.objects.filter(pub_date__week_day__gte=2)
(Для этого запроса не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса различается в разных баз данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date, которая попадает на понедельник (день 2 недели), независимо от месяца или года, в котором это происходит. Дни недели индексируются с днем 1, являющимся воскресеньем, и днем 7, являющимся субботой.
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
iso_week_day
Для полей даты и datetime — точное соответствие дню недели ISO 8601. Позволяет цепочку дополнительных поисков по полям.
Принимает целое число, представляющее день недели от 1 (понедельник) до 7 (воскресенье).
Пример:
Entry.objects.filter(pub_date__iso_week_day=1) Entry.objects.filter(pub_date__iso_week_day__gte=1)
(Для этого запроса не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса различается в разных баз данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date, которая попадает на понедельник (день 1 недели), независимо от месяца или года, в котором это происходит. Дни недели индексируются с днем 1, являющимся понедельником, и днем 7, являющимся воскресеньем.
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
quarter
Для полей даты и datetime — соответствие кварталу года. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 1 до 4, представляющее квартал года.
Пример получения записей во втором квартале (с 1 апреля по 30 июня):
Entry.objects.filter(pub_date__quarter=2)
(Для этого запроса не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса различается в разных баз данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
time
Для полей datetime преобразует значение как время. Позволяет цепочку дополнительных поисков по полям. Принимает значение datetime.time.
Пример:
Entry.objects.filter(pub_date__time=datetime.time(14, 30)) Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(Для этого запроса не приводится эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса различается в разных баз данных.)
Когда USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
hour
Для полей datetime и time — точное соответствие часу. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 23.
Пример:
Event.objects.filter(timestamp__hour=23) Event.objects.filter(time__hour=5) Event.objects.filter(timestamp__hour__gte=12)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(Точная синтаксическая конструкция SQL зависит от используемой базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
minute
Для полей datetime и time — точное соответствие минуте. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__minute=29) Event.objects.filter(time__minute=46) Event.objects.filter(timestamp__minute__gte=29)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(Точная синтаксическая конструкция SQL зависит от используемой базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
second
Для полей datetime и time — точное соответствие секунде. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__second=31) Event.objects.filter(time__second=2) Event.objects.filter(timestamp__second__gte=31)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(Точная синтаксическая конструкция SQL зависит от используемой базы данных.)
Когда USE_TZ равно True, поля datetime преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
isnull
Принимает либо True, либо False, что соответствует SQL-запросам IS NULL и IS NOT NULL соответственно.
Пример:
Entry.objects.filter(pub_date__isnull=True)
Эквивалент SQL:
SELECT ... WHERE pub_date IS NULL;
regex
Соответствие регулярному выражению (чувствительно к регистру).
Синтаксис регулярных выражений соответствует синтаксису используемого движка базы данных. В случае SQLite, который не имеет встроенной поддержки регулярных выражений, эта функция предоставляется пользовательской функцией REGEXP (на Python), и синтаксис регулярных выражений, следовательно, соответствует синтаксису модуля re Python.
Пример:
Entry.objects.get(title__regex=r"^(An?|The) +")
Эквиваленты SQL:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Рекомендуется использовать строковые литералы (например, r'foo' вместо 'foo') для передачи синтаксиса регулярных выражений.
iregex
Соответствие регулярному выражению (нечувствительно к регистру).
Пример:
Entry.objects.get(title__iregex=r"^(an?|the) +")
Эквиваленты SQL:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Функции агрегации
Django предоставляет следующие функции агрегации в модуле django.db.models. Подробнее о том, как использовать эти функции агрегации, см. в руководстве по агрегации. См. документацию Aggregate, чтобы узнать, как создавать свои агрегаты.
Предупреждение
SQLite не может обрабатывать агрегацию по полям даты/времени без дополнительных настроек. Это связано с тем, что в SQLite нет встроенных полей даты/времени, и Django в настоящее время эмулирует эти функции с помощью текстового поля. Попытки использовать агрегацию по полям даты/времени в SQLite приведут к ошибке NotSupportedError.
Пустые наборы результатов или группы
Функции агрегации возвращают None при использовании с пустым QuerySet или группой. Например, функция агрегации Sum возвращает None вместо 0, если QuerySet содержит записи или для любой пустой группы в непустом QuerySet. Чтобы вернуть другое значение вместо этого, определите аргумент default. Count — исключение из этого правила; она возвращает 0 если QuerySet пусто, так как Count не поддерживает аргумент default.
Все агрегаты имеют следующие параметры:
expressions
Строки, ссылающиеся на поля модели, преобразования поля или выражения запроса.
output_field
Необязательный аргумент, представляющий поле модели возвращаемого значения.
Примечание
При комбинировании нескольких типов полей Django может определить output_field только если все поля имеют один и тот же тип. В противном случае вам необходимо указать output_field самостоятельно.
filter
Необязательное Q object, которое используется для фильтрации строк, которые агрегируются.
См. Условную агрегацию и Фильтрацию по аннотациям для примеров использования.
default
Необязательный аргумент, позволяющий указать значение по умолчанию, если в наборе запросов (или группировке) нет записей.
**extra
Ключевые аргументы, которые могут предоставить дополнительный контекст для SQL-запроса, сгенерированного агрегацией.
Avg
-
class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra) -
Возвращает среднее значение заданного выражения, которое должно быть числовым, если не указано иное
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, возвращаемое значение будет дисперсией выборки.
- По умолчанию псевдоним:
Инструменты, связанные с запросами
Q() объекты
-
class Q
Объект Q() представляет собой SQL-условие, которое может быть использовано в операциях, связанных с базой данных. Он похож на то, как объект F() представляет значение поля модели или аннотации. Они позволяют определять и повторно использовать условия, а также комбинировать их с помощью операторов, таких как | (OR), & (AND), и ^ (XOR). См. Сложные запросы с Q-объектами.
Prefetch() объекты
-
class Prefetch(lookup, queryset=None, to_attr=None)
Объект Prefetch() может использоваться для управления работой prefetch_related().
Аргумент lookup описывает отношения для отслеживания и работает так же, как строковые выражения, передаваемые в prefetch_related(). Например:
>>> from django.db.models import Prefetch
>>> Question.objects.prefetch_related(Prefetch("choice_set")).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch("choice_set"))
<QuerySet [<Question: What's up?>]>
Аргумент queryset предоставляет базовый QuerySet для данного выражения. Это полезно для дальнейшей фильтрации операции предварительной выборки или вызова select_related() из предварительно выбранного отношения, тем самым ещё больше уменьшая количество запросов:
>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
<QuerySet [<Choice: The sky>]>
>>> prefetch = Prefetch("choice_set", queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: The sky>]>
Аргумент to_attr устанавливает результат операции предварительной выборки в пользовательское свойство:
>>> prefetch = Prefetch("choice_set", queryset=voted_choices, to_attr="voted_choices")
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
[<Choice: The sky>]
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
Примечание
При использовании to_attr результат предварительной выборки хранится в списке. Это может значительно ускорить работу по сравнению с традиционными вызовами prefetch_related которые сохраняют кэшированный результат внутри экземпляра QuerySet.
prefetch_related_objects()
Асинхронная версия: aprefetch_related_objects()
Выполняет предварительную выборку указанных выражений для итерируемого набора экземпляров моделей. Это полезно в коде, который получает список экземпляров моделей, а не QuerySet, например, при извлечении моделей из кэша или их ручном создании.
Передайте итерируемый набор экземпляров моделей (все должны быть одного класса) и выражения или объекты Prefetch, которые вы хотите предварительно выбрать. Например:
>>> from django.db.models import prefetch_related_objects >>> restaurants = fetch_top_restaurants_from_cache() # A list of Restaurants >>> prefetch_related_objects(restaurants, "pizzas__toppings")
При использовании нескольких баз данных с prefetch_related_objects, запрос предварительной выборки будет использовать базу данных, связанную с экземпляром модели. Это можно переопределить, используя пользовательский набор запросов в связанном выражении.
aprefetch_related_objects() функция была добавлена.
FilteredRelation() объекты
-
class FilteredRelation(relation_name, *, condition=Q()) -
-
relation_name -
Имя поля, по которому вы хотите отфильтровать отношение.
-
condition -
Объект
Qдля управления фильтрацией.
-
FilteredRelation используется с annotate() для создания условия ON, когда выполняется JOIN. Он не действует на стандартное отношение, а на имя аннотации (pizzas_vegetarian в примере ниже).
Например, чтобы найти рестораны, в которых есть вегетарианские пиццы с 'mozzarella' в названии:
>>> from django.db.models import FilteredRelation, Q >>> Restaurant.objects.annotate( ... pizzas_vegetarian=FilteredRelation( ... "pizzas", ... condition=Q(pizzas__vegetarian=True), ... ), ... ).filter(pizzas_vegetarian__name__icontains="mozzarella")
Если пицц много, это запросный набор работает лучше, чем:
>>> Restaurant.objects.filter( ... pizzas__vegetarian=True, ... pizzas__name__icontains="mozzarella", ... )
потому что фильтрация в WHERE клаузе первого запросного набора будет работать только с вегетарианскими пиццами.
FilteredRelation не поддерживает:
-
QuerySet.only()иprefetch_related(). - A
GenericForeignKey, унаследованный от родительской модели.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.0/ref/models/querysets/