Справочник по API QuerySet
¶
Этот документ описывает детали API QuerySet
. Он основан на материале, представленном в руководствах модель и запросы к базе данных, так что вы, вероятно, захотите прочитать и понять эти документы, прежде чем читать этот.
Throughout this reference we’ll use the example blog models presented in the database query guide.
Когда вычисляется QuerySet
¶
Внутренне QuerySet
может быть создан, отфильтрован, нарезан и, как правило, передан без фактического запроса к базе данных. На самом деле никаких действий с базой данных не происходит, пока вы не сделаете что-то для оценки набора запросов.
Вы можете вычислить QuerySet
следующими способами:
Итерация.
QuerySet
является итеративным, и он выполняет свой запрос к базе данных при первой итерации по нему. Например, это напечатает заголовок всех записей в базе данных:for e in Entry.objects.all(): print(e.headline)
Примечание: не используйте это, если все, что вы хотите сделать, это определить, существует ли хотя бы один результат. Более эффективно использовать
exists()
.Асинхронная итерация.. По
QuerySet
можно также выполнять итерацию с помощьюasync for
:async for e in Entry.objects.all(): results.append(e)
И синхронные, и асинхронные итераторы QuerySets используют один и тот же базовый кэш.
Changed in Django Development version:Support for asynchronous iteration was added.
Срезы. Как объяснено в Ограничение QuerySet,
QuerySet
может быть нарезан, используя синтаксис Python для срезов массивов. Срез невычисленногоQuerySet
обычно возвращает другой невычисленныйQuerySet
, но Django выполнит запрос к базе данных, если вы используете параметр «step» синтаксиса среза, и вернет список. СрезQuerySet
, который был вычислен, также возвращает список.Также обратите внимание, что даже если срез невычисленного
QuerySet
возвращает другой невычисленныйQuerySet
, дальнейшее его изменение (например, добавление дополнительных фильтров или изменение порядка) недопустимо, поскольку это плохо переводится в SQL и не будет иметь четкого значения.Pickling/Кэширование. См. следующий раздел для получения подробной информации о том, что происходит при pickling QuerySets. Для целей этого раздела важно, чтобы результаты считывались из базы данных.
repr().
QuerySet
вычисляется, когда вы вызываетеrepr()
для него. Это удобно для интерактивного интерпретатора Python, поэтому вы можете сразу увидеть свои результаты при интерактивном использовании API.len().
QuerySet
вычисляется, когда вы вызываетеlen()
для него. Это, как вы могли ожидать, возвращает длину списка результатов.Примечание. Если вам нужно только определить количество записей в наборе (и вам не нужны фактические объекты), гораздо эффективнее обрабатывать количество на уровне базы данных, используя SQL
SELECT COUNT (*)
. Именно по этой причине Django предоставляет методcount()
.list(). Принудительное вычисление
QuerySet
путем вызоваlist()
для него. Например:entry_list = list(Entry.objects.all())
bool(). Тестирование
QuerySet
в логическом контексте, например, с использованиемbool()
,or
,and
или оператораif
, вызовет выполнение запроса. Если есть хотя бы один результат,QuerySet
равенTrue
, иначеFalse
. Например:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")
Примечание. Если вы хотите определить, существует ли хотя бы один результат (и вам не нужны реальные объекты), более эффективно использовать
exists()
.
Pickling QuerySet
¶
Если вы используете pickle
для QuerySet
, это загрузит все результаты в память. Pickling обычно используется в качестве предвестника кеширования, и когда кешированный набор запросов перезагружается, вы хотите, чтобы результаты уже присутствовали и были готовы к использованию (чтение из базы данных может занять некоторое время, что отрицательно сказывается на цели кеширования). Это означает, что когда вы unpickle QuerySet
, он содержит результаты в тот момент, когда он был выбран, а не результаты, которые в данный момент находятся в базе данных.
Если вы хотите pickle только необходимую информацию для воссоздания QuerySet
из базы данных позднее, выберите атрибут query
для QuerySet
. Затем вы можете воссоздать исходный QuerySet
(без каких-либо результатов), используя код, подобный следующему:
>>> import pickle
>>> query = pickle.loads(s) # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query # Restore the original 'query'.
Атрибут query
является непрозрачным объектом. Он представляет собой внутреннюю часть конструкции запроса и не является частью общедоступного API. Тем не менее, безопасно (и полностью поддерживается) pickle и unpickle содержимое атрибута, как описано здесь.
Ограничения на QuerySet.values_list()
Если вы воссоздадите QuerySet.values_list()
с использованием упакованного атрибута query
, он будет преобразован в QuerySet.values()
:
>>> import pickle
>>> qs = Blog.objects.values_list('id', 'name')
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
QuerySet
API¶
Вот формальное объявление QuerySet
:
-
class
QuerySet
(model=None, query=None, using=None, hints=None)[исходный код]¶ Обычно, когда вы будете взаимодействовать с
QuerySet
, вы будете использовать его фильтры цепочки. Для этого большинство методовQuerySet
возвращают новые наборы запросов. Эти методы подробно описаны ниже в этом разделе.The
QuerySet
class has the following public attributes you can use for introspection:-
ordered
¶ True
, еслиQuerySet
упорядочен - т.е. имеетorder_by()
или сортировку по умолчанию для модели, иначеFalse
.
-
db
¶ База данных, которая будет использоваться, если этот запрос выполняется сейчас.
Примечание
Параметр
query
дляQuerySet
существует для того, чтобы специализированные подклассы запросов могли реконструировать внутреннее состояние запроса. Значение параметра является непрозрачным представлением этого состояния запроса и не является частью общедоступного API.-
Методы, которые возвращают новый QuerySet
¶
Django предоставляет ряд методов уточнения QuerySet
, которые изменяют либо типы результатов, возвращаемых QuerySet
, либо способ выполнения его SQL-запроса.
Примечание
Эти методы не выполняют запросы к базе данных, поэтому они безопасны для запуска в асинхронном коде, и не имеют отдельных асинхронных версий.
filter()
¶
-
filter
(*args, **kwargs)¶
Возвращает новый QuerySet
, содержащий объекты, которые соответствуют заданным параметрам поиска.
Параметры поиска (**kwargs
) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются через И
в базовом операторе SQL.
If you need to execute more complex queries (for example, queries with OR
statements),
you can use Q objects
(*args
).
exclude()
¶
-
exclude
(*args, **kwargs)¶
Возвращает новый QuerySet
, содержащий объекты, которые не соответствуют указанным параметрам поиска.
Параметры поиска (**kwargs
) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются с помощью AND
в базовом операторе SQL, и все это заключено в NOT()
.
Этот пример исключает все записи, чье pub_date
позже, чем 2005-1-3 И чьи headline
равно «Hello»:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
В терминах SQL это оценивается как:
SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
В этом примере исключаются все записи, чье pub_date
позже, чем 2005-1-3 ИЛИ с заголовком «Hello»:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
В терминах SQL это оценивается как:
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'
Обратите внимание, что второй пример является более ограниченным.
If you need to execute more complex queries (for example, queries with OR
statements),
you can use Q objects
(*args
).
annotate()
¶
-
annotate
(*args, **kwargs)¶
Аннотирует каждый объект в QuerySet
с помощью предоставленного списка выражений запроса. Выражение может быть простым значением, ссылкой на поле в модели (или любых связанных моделях) или агрегированным выражением (средние значения, суммы и т.д.), которое было вычислено для объектов, связанных с объектами в QuerySet
.
Каждый аргумент annotate()
является аннотацией, которая будет добавлена к каждому объекту в QuerySet
, который возвращается.
Функции агрегации, предоставляемые Django, описаны в Функции агрегации ниже.
Аннотации, указанные с помощью ключевых аргументов, будут использовать ключевое слово в качестве псевдонима для аннотации. Для анонимных аргументов будет создан псевдоним, основанный на имени агрегатной функции и агрегируемого поля модели. Только агрегатные выражения, которые ссылаются на одно поле, могут быть анонимными аргументами. Все остальное должно быть ключевым аргументом.
Например, если вы манипулировали списком блогов, вы можете определить, сколько записей было сделано в каждом блоге:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Модель Blog
не определяет атрибут entry__count
сама по себе, но с помощью ключевого аргумента для указания агрегатной функции вы можете контролировать имя аннотации:
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
Подробное обсуждение агрегации смотрите в руководство по агрегации.
alias()
¶
-
alias
(*args, **kwargs)¶
То же, что annotate()
, но вместо аннотирования объектов в QuerySet
сохраняет выражение для последующего повторного использования с другими методами QuerySet
. Это полезно, когда результат самого выражения не нужен, но он используется для фильтрации, упорядочивания или как часть сложного выражения. Если не выбрать неиспользуемое значение, из базы данных удаляется избыточная работа, что должно привести к повышению производительности.
Например, если вы хотите найти блоги с более чем 5 записями, но не интересуетесь точным количеством записей, вы можете сделать это:
>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count('entry')).filter(entries__gt=5)
alias()
можно использовать вместе с annotate()
, exclude()
, filter()
, order_by()
и update()
. Чтобы использовать выражение с псевдонимом с другими методами (например aggregate()
), вы должны преобразовать его в аннотацию:
Blog.objects.alias(entries=Count('entry')).annotate(
entries=F('entries'),
).aggregate(Sum('entries'))
filter()
и order_by()
могут принимать выражения напрямую, но построение и использование выражений часто не происходит в одном и том же месте (например, метод QuerySet
создает выражения для последующего использования в представлениях). alias()
позволяет создавать сложные выражения постепенно, возможно, охватывая несколько методов и модулей, ссылаться на части выражения по их псевдонимам и использовать только annotate()
для окончательного результата.
order_by()
¶
-
order_by
(*fields)¶
По умолчанию результаты, возвращаемые QuerySet
, упорядочиваются с помощью кортежа, заданного параметром ordering
в классе Meta
модели. Вы можете переопределить это для каждого QuerySet
, используя метод order_by
.
Пример:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
Приведенный выше результат будет упорядочен по убыванию pub_date
, затем по возрастанию headline
. Отрицательный знак перед "-pub_date"
указывает нисходящий порядок. Восходящий порядок подразумевается. Чтобы упорядочить случайным образом, используйте "?"
, например так:
Entry.objects.order_by('?')
Примечание: запросы order_by('?')
могут быть дорогими и медленными, в зависимости от используемой вами базы данных.
Чтобы упорядочить по полю в другой модели, используйте тот же синтаксис, что и при запросах к отношениям модели. То есть имя поля, за которым следует двойное подчеркивание (__
), за которым следует имя поля в новой модели и т.д. для всех моделей, к которым вы хотите присоединиться. Например:
Entry.objects.order_by('blog__name', 'headline')
Если вы попытаетесь упорядочить по полю, которое относится к другой модели, Django будет использовать упорядочение по умолчанию для связанной модели или упорядочить по первичному ключу связанной модели, если не указано Meta.ordering
. Например, поскольку модель Blog
не имеет установленного порядка по умолчанию:
Entry.objects.order_by('blog')
…идентично:
Entry.objects.order_by('blog__id')
Если бы Blog
имел ordering = ['name']
, то первый набор запросов был бы идентичен:
Entry.objects.order_by('blog__name')
Вы также можете упорядочить выражения запроса, вызвав asc()
или desc()
в выражении:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
asc()
и desc()
имеют аргументы (nulls_first
и nulls_last
), которые управляют сортировкой нулевых значений.
Будьте осторожны при упорядочении по полям в связанных моделях, если вы также используете different()
. Смотрите примечания в different()
для объяснения того, как упорядочение связанной модели может изменить ожидаемые результаты.
Примечание
Допустимо указывать многозначное поле для упорядочения результатов по (например, полю a 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
с несколькими 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()
лишние выбранные поля будут игнорироваться.Calling
only()
anddefer()
aftervalues()
doesn’t make sense, so doing so will raise aTypeError
.Объединение преобразований и агрегирования требует использования двух вызовов
annotate()
, либо явно, либо в качестве именованных аргументов дляvalues()
. Как и выше, если преобразование зарегистрировано в соответствующем типе поля, первоеannotate()
может быть опущено, поэтому следующие примеры эквивалентны:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values( ... entry__authors__name__lower=Lower('entry__authors__name') ... ).annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate( ... entry__authors__name__lower=Lower('entry__authors__name') ... ).values('entry__authors__name__lower').annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
Это полезно, когда вы знаете, что вам понадобятся значения только из небольшого числа доступных полей, и вам не понадобятся функциональные возможности объекта экземпляра модели. Более эффективно выбирать только те поля, которые вам нужны.
Наконец, обратите внимание, что вы можете вызывать filter()
, order_by()
и т.д. после вызова values()
, это означает, что эти два вызова идентичны:
Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()
Люди, которые сделали Django, предпочитают сначала поместить все методы, влияющие на SQL, а затем (необязательно) любые методы, влияющие на вывод (такие как values()
), но это не имеет большого значения. Это ваш шанс по-настоящему выставить напоказ свой индивидуализм.
Вы также можете ссылаться на поля в связанных моделях с обратными связями через атрибуты OneToOneField
, ForeignKey
и ManyToManyField
:
>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Предупреждение
Потому что ManyToManyField
атрибуты и обратные отношения могут иметь несколько связанных строк, в том числе они могут повлиять на размер набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в ваш запрос values()
, и в этом случае будут возвращены все возможные комбинации.
Специальные значения для JSONField
в SQLite
Из-за того, как функции SQL JSON_EXTRACT
и JSON_TYPE
реализованы в SQLite, и отсутствия типа данных BOOLEAN
, values()
будет возвращать True
, False
и None
вместо "true"
, "false"
и "null"
строк для JSONField
ключевых преобразований.
values_list()
¶
-
values_list
(*fields, flat=False, named=False)¶
Это похоже на values()
, за исключением того, что вместо возврата словарей он возвращает кортежи при повторении. Каждый кортеж содержит значение из соответствующего поля или выражения, переданное в вызов values_list()
- поэтому первый элемент является первым полем и т.д. Например:
>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>
Если вы передаете только одно поле, вы также можете передать параметр flat
. Если True
, это будет означать, что возвращаемые результаты будут единичными значениями, а не кортежем. Пример должен прояснить разницу:
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
Ошибочно передавать в flat
, когда имеется более одного поля.
Вы можете передать named=True
для получения результатов в виде namedtuple()
:
>>> Entry.objects.values_list('id', 'headline', named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
Использование именованного кортежа может сделать результаты более читабельными за счет небольшого снижения производительности за преобразование результатов в именованный кортеж.
Если вы не передадите никаких значений в values_list()
, он вернет все поля в модели в том порядке, в котором они были объявлены.
Общей необходимостью является получение определенного значения поля определенного экземпляра модели. Для этого используйте values_list()
, а затем get()
:
>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'
values()
и values_list()
предназначены для оптимизации для конкретного случая использования: извлечение подмножества данных без затрат на создание экземпляра модели. Эта метафора разваливается при работе со многими ко многим и другими многозначными отношениями (такими как отношение «один ко многим» обратного внешнего ключа), потому что предположение «одна строка, один объект» не выполняется.
Например, обратите внимание на поведение при запросе через ManyToManyField
:
>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
Авторы с несколькими записями появляются несколько раз, а авторы без записей имеют None
для заголовка записи.
Аналогично, при запросе обратного внешнего ключа, None
появляется для записей, не имеющих автора:
>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
Специальные значения для JSONField
в SQLite
Из-за того, как функции SQL JSON_EXTRACT
и JSON_TYPE
реализованы в SQLite, и отсутствия типа данных BOOLEAN
, values_list()
будет возвращать True
, False
и None
вместо "true"
, "false"
и "null"
строк для JSONField
ключевых преобразований.
dates()
¶
-
dates
(field, kind, order='ASC')¶
Возвращает QuerySet
, который вычисляет список объектов datetime.date
, представляющих все доступные даты определенного вида в QuerySet
.
field
должно быть именем DateField
вашей модели. kind
должен быть либо "year"
, "month"
, "week"
, либо "day"
. Каждый объект datetime.date
в списке результатов «усекается» до заданного type
.
"year"
возвращает список всех различных значений года."month"
возвращает список всех различных значений года/месяца."week"
возвращает список всех различных значений года/недели. Все даты будут понедельником."day"
возвращает список всех различных значений года/месяца/дня.
order
, который по умолчанию равен 'ASC'
, должен быть либо 'ASC'
, либо 'DESC'
. Это указывает, как сортировать результаты.
Примеры:
>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'week')
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]
datetimes()
¶
-
datetimes
(field_name, kind, order='ASC', tzinfo=None, is_dst=None)¶
Возвращает QuerySet
, который оценивает список объектов datetime.datetime
, представляющих все доступные даты определенного вида в содержимом QuerySet
.
field_name` должно быть именем ``DateTimeField
вашей модели.
kind
должен быть одним из: "year"
, "month"
, "week"
, "day"
, "hour"
, "minute"
, "second"
. Каждый объект datetime.datetime
в списке результатов «усекается» до заданного type
.
order
, который по умолчанию равен 'ASC'
, должен быть либо 'ASC'
, либо 'DESC'
. Это указывает, как сортировать результаты.
tzinfo
определяет часовой пояс, в который конвертируются даты и время перед усечением. Действительно, данная дата и время имеют разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo
. Если это None
, Django использует текущий часовой пояс. Это не действует, если USE_TZ
равно False
.
is_dst
указывает, должен ли pytz
интерпретировать несуществующие и неоднозначные даты в летнее время. По умолчанию (когда is_dst=None
), pytz
выдает исключение для таких datetime.
Не рекомендуется, начиная с версии 4.0: The is_dst
parameter is deprecated and will be removed in Django 5.0.
Примечание
Эта функция выполняет преобразование часового пояса непосредственно в базе данных. Как следствие, ваша база данных должна иметь возможность интерпретировать значение tzinfo.tzname(None)
. Это приводит к следующим требованиям:
- SQLite: no requirements. Conversions are performed in Python.
- PostgreSQL: никаких требований (см. Часовые пояса).
- Oracle: нет требований (см. Выбор файла часового пояса).
- MySQL: загрузить таблицы часовых поясов с помощью mysql_tzinfo_to_sql.
none()
¶
-
none
()¶
Calling none()
will create a queryset that never returns any objects and no
query will be executed when accessing the results. A qs.none()
queryset
is an instance of 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')
In addition, only LIMIT
, OFFSET
, COUNT(*)
, ORDER BY
, and
specifying columns (i.e. slicing, count()
, exists()
,
order_by()
, and values()
/values_list()
) are allowed
on the resulting QuerySet
. Further, databases place restrictions on
what operations are allowed in the combined queries. For example, most
databases don’t allow LIMIT
or OFFSET
in the combined queries.
intersection()
¶
-
intersection
(*other_qs)¶
Использует оператор SQL INTERSECT
для возврата общих элементов двух или более QuerySet
’ов. Например:
>>> qs1.intersection(qs2, qs3)
Смотрите union()
для некоторых ограничений.
difference()
¶
-
difference
(*other_qs)¶
Использует оператор SQL EXCEPT
для хранения только элементов, присутствующих в QuerySet
, но не в каких-либо других QuerySet
’ах. Например:
>>> qs1.difference(qs2, qs3)
Смотрите union()
для некоторых ограничений.
extra()
¶
-
extra
(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)¶
Иногда синтаксис запроса Django сам по себе не может легко выразить сложное предложение WHERE
. Для этих крайних случаев Django предоставляет модификатор extra()
QuerySet
- ловушку для вставки определенных предложений в SQL, генерируемый QuerySet
.
Используйте этот метод в качестве крайней меры
Это старый API, который мы запретим в какой-то момент в будущем. Используйте его, только если вы не можете выразить свой запрос, используя другие методы набора запросов. Если вам нужно его использовать, пожалуйста, отправьте заявку <https://code.djangoproject.com/newticket>`_, используя ключевое слово QuerySet.extra keyword в вашем случае использования (сначала проверьте список существующих заявок), чтобы мы могли усовершенствовать 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!
Вы можете прочитать больше о том, как работает в Django Защита от SQL-инъекций.
По определению, эти дополнительные поиски могут не переноситься на разные механизмы баз данных (потому что вы явно пишете код SQL) и нарушают принцип DRY, поэтому вам следует избегать их, если это возможно.
Укажите одну или несколько params
, select
, where
или tables
. Ни один из аргументов не требуется, но вы должны использовать хотя бы один из них.
select
Аргумент
select
позволяет добавлять дополнительные поля в предложениеSELECT
. Это должен быть словарь, сопоставляющий имена атрибутов с предложениями SQL для использования для вычисления этого атрибута.Пример:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
В результате каждый объект
Entry
будет иметь дополнительный атрибут,is_recent
, логическое значение, представляющее, является лиpub_date
больше, чем 1 января 2006 года.Django вставляет данный фрагмент SQL непосредственно в оператор
SELECT
, поэтому полученный SQL-код из приведенного выше примера будет выглядеть примерно так:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Следующий пример более продвинутый, он выполняет подзапрос, чтобы дать каждому результирующему объекту
Blog
атрибутentry_count
, целое число связанных объектовEntry
:Blog.objects.extra( select={ 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' }, )
В данном конкретном случае мы используем тот факт, что запрос уже содержит таблицу
blog_blog
в своем предложенииFROM
.Результирующий SQL из приведенного выше примера будет:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Обратите внимание, что круглые скобки, требуемые большинством механизмов баз данных для подзапросов, не требуются в предложениях
select
Django. Также обратите внимание, что некоторые базы данных, такие как некоторые версии MySQL, не поддерживают подзапросы.В некоторых редких случаях вам может потребоваться передать параметры фрагментам SQL в
extra(select=...)
. Для этого используйте параметрselect_params
.Это будет работать, например:
Blog.objects.extra( select={'a': '%s', 'b': '%s'}, select_params=('one', 'two'), )
Если вам нужно использовать литерал
%s
внутри строки выбора, используйте последовательность%%s
.where
/tables
Вы можете определить явные выражения SQL
WHERE
- возможно, для выполнения неявных объединений - используяwhere
. Вы можете вручную добавить таблицы в предложение SQLFROM
, используяtables
.where
иtables
принимают список строк. Всеwhere
параметры имеют значение «AND» для любых других критериев поиска.Пример:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
…переводит (примерно) в следующий SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Будьте осторожны при использовании параметра
tables
, если вы указываете таблицы, которые уже используются в запросе. Когда вы добавляете дополнительные таблицы с помощью параметраtables
, Django предполагает, что вы хотите, чтобы таблица включала дополнительное время, если оно уже включено. Это создает проблему, так как имя таблицы будет иметь псевдоним. Если таблица появляется в операторе SQL несколько раз, второе и последующие вхождения должны использовать псевдонимы, чтобы база данных могла различать их. Если вы ссылаетесь на дополнительную таблицу, которую вы добавили в дополнительный параметрwhere
, это приведет к ошибкам.Обычно вы будете добавлять только дополнительные таблицы, которые еще не отображаются в запросе. Однако, если описанный выше случай действительно имеет место, есть несколько решений. Во-первых, посмотрите, сможете ли вы обойтись без включения дополнительной таблицы и используйте ту, которая уже есть в запросе. Если это невозможно, поместите ваш вызов
extra()
в начале конструкции набора запросов, чтобы ваша таблица использовалась первой в этой таблице. Наконец, если ничего не помогает, посмотрите на полученный запрос и перепишите свое дополнение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()
, ниже) предназначены только для расширенных вариантов использования. Они обеспечивают оптимизацию, когда вы тщательно проанализировали свои запросы и точно поняли, какая информация вам нужна, и измерили, что разница между возвратом необходимых вам полей и полным набором полей для модели будет значительной.
Even if you think you are in the advanced use-case situation, only use
defer()
when you cannot, at queryset load time, determine if you will
need the extra fields or not. If you are frequently loading and using a
particular subset of your data, the best choice you can make is to
normalize your models and put the non-loaded data into a separate model
(and database table). If the columns must stay in the one table for some
reason, create a model with Meta.managed = False
(see the
managed attribute
documentation)
containing just the fields you normally need to load and use that where you
might otherwise call defer()
. This makes your code more explicit to the
reader, is slightly faster and consumes a little less memory in the Python
process.
Например, обе эти модели используют одну и ту же базовую таблицу базы данных:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = 'app_largetable'
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = 'app_largetable'
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer('f2')
Если в неуправляемой модели необходимо дублировать многие поля, может быть лучше создать абстрактную модель с общими полями, а затем иметь неуправляемые и управляемые модели, наследуемые от абстрактной модели.
only()
¶
-
only
(*fields)¶
Метод only()
по сути противоположен методу defer()
. Только поля, переданные в этот метод и не уже указанные как отложенные, загружаются немедленно при оценке набора запросов.
If you have a model where almost all the fields need to be deferred, using
only()
to specify the complementary set of fields can result in simpler
code.
Предположим, у вас есть модель с полями 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()
, также является ошибкой.
Как и в случае с defer()
, вы не можете получить доступ к незагруженным полям из асинхронного кода и ожидать, что они загрузятся. Вместо этого вы получите исключение SynchronousOnlyOperation
. Убедитесь, что все поля, к которым вы можете получить доступ, находятся в вашем вызове only()
.
using()
¶
-
using
(alias)¶
Этот метод предназначен для указания какую базу данных QuerySet
будет использовать, если вы используете более одной базы данных. Единственный аргумент, который принимает этот метод - это псевдоним базы данных, как определено в DATABASES
.
Например:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
select_for_update()
¶
-
select_for_update
(nowait=False, skip_locked=False, of=(), no_key=False)¶
Возвращает набор запросов, который блокирует строки до конца транзакции, генерируя оператор SQL SELECT ... FOR UPDATE
для поддерживаемых баз данных.
Например:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
Когда набор запросов выполняется (в данном случае for entry in entries
), все совпадающие записи будут заблокированы до конца блока транзакции, что означает, что другие транзакции не смогут изменить или получить блокировки для них.
Обычно, если другая транзакция уже получила блокировку в одной из выбранных строк, запрос будет блокироваться до тех пор, пока блокировка не будет снята. Если это не то поведение, которое вам нужно, вызовите select_for_update(nowait=True)
. Это сделает вызов неблокирующим. Если конфликтующая блокировка уже получена другой транзакцией, то при оценке набора запросов будет вызвано DatabaseError
. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True)
. nowait
и skip_locked
являются взаимоисключающими и попытки вызвать select_for_update()
с включенными обеими опциями приведут к ValueError
.
По умолчанию select_for_update()
блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанных в select_related()
, блокируются в дополнение к строкам модели набора запросов. Если это нежелательно, укажите связанные объекты, которые вы хотите заблокировать, в select_for_update(of=(...))
, используя тот же синтаксис полей, что и select_related()
. Используйте значение 'self'
для ссылки на модель набора запросов.
Блокировка родительских моделей в select_for_update(of=(...))
Если вы хотите заблокировать родительские модели при использовании наследование нескольких таблиц, вы должны указать поля родительской ссылки (по умолчанию <parent_model_name>_ptr
) в аргументе of
. Например:
Restaurant.objects.select_for_update(of=('self', 'place_ptr'))
Using select_for_update(of=(...))
with specified fields
Если вы хотите заблокировать модели и указать выбранные поля, например, используя values()
, вы должны выбрать хотя бы одно поле из каждой модели в аргументе of
. Модели без выбранных полей не будут заблокированы.
Только в PostgreSQL вы можете передать no_key=True
, чтобы получить более слабую блокировку, которая по-прежнему позволяет создавать строки, которые просто ссылаются на заблокированные строки (например, через внешний ключ), пока блокировка установлена. В документации PostgreSQL есть более подробная информация о режимах блокировки на уровне строк.
Вы не можете использовать select_for_update()
для обнуляемых отношений:
>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
Чтобы избежать этого ограничения, вы можете исключить нулевые объекты, если вам не нужны их значения:
>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
The postgresql
, oracle
, and mysql
database backends support
select_for_update()
. However, MariaDB only supports the nowait
argument, MariaDB 10.6+ also supports the skip_locked
argument, and MySQL
8.0.1+ supports the nowait
, skip_locked
, and of
arguments. The
no_key
argument is only supported on PostgreSQL.
Передача nowait=True
, skip_locked=True
, no_key=True
или of
в select_for_update()
с использованием бэкэндов базы данных, которые не поддерживают эти параметры, например как MySQL, вызывает ошибку NotSupportedError
. Это предотвращает неожиданную блокировку кода.
Оценка набора запросов с помощью select_for_update()
в режиме автоматической фиксации на бэкэндах, которые поддерживают SELECT ... FOR UPDATE
, является ошибкой TransactionManagementError
, поскольку строки не заблокированы в этом случае. Если это разрешено, это будет способствовать повреждению данных и может быть легко вызвано вызовом кода, который предполагается запустить в транзакции вне ее.
Использование select_for_update()
на бэкэндах, которые не поддерживают SELECT ... FOR UPDATE
(таких как SQLite), не будет иметь никакого эффекта. SELECT ... FOR UPDATE
не будет добавлен к запросу, и ошибка не возникнет, если select_for_update()
используется в режиме автоматической фиксации.
Предупреждение
Хотя select_for_update()
обычно дает сбой в режиме автоматической фиксации, поскольку TestCase
автоматически оборачивает каждый тест в транзакцию, вызывая select_for_update()
в TestCase
даже вне блока atomic()
(возможно, неожиданно) пройдет без вызова TransactionManagementError
. Для правильного тестирования select_for_update()
вы должны использовать TransactionTestCase
.
Некоторые выражения могут не поддерживаться
PostgreSQL не поддерживает select_for_update()
с выражениями Window
.
raw()
¶
-
raw
(raw_query, params=(), translations=None, using=None)¶
Принимает необработанный SQL-запрос, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet
. Этот экземпляр RawQuerySet
может быть повторен, как обычный QuerySet
, для предоставления экземпляров объекта.
Смотрите Выполнение необработанных SQL-запросов для получения дополнительной информации.
Предупреждение
raw()
всегда запускает новый запрос и не учитывает предыдущую фильтрацию. Как таковой, он обычно должен вызываться из Manager
или из свежего QuerySet
.
Операторы, которые возвращают новый QuerySet
¶
Комбинированные наборы запросов должны использовать одну и ту же модель.
AND (&
)¶
Объединяет два QuerySet
’а, используя оператор SQL AND
.
Следующее эквивалентно:
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))
SQL-эквивалент:
SELECT ... WHERE x=1 AND y=2
OR (|
)¶
Объединяет два 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
|
не является коммутативной операцией, так как могут быть сгенерированы различные (хотя и эквивалентные) запросы.
XOR (^
)¶
Combines two QuerySet
s using the SQL XOR
operator.
Следующее эквивалентно:
Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) ^ Q(y=2))
SQL-эквивалент:
SELECT ... WHERE x=1 XOR y=2
Примечание
XOR
поддерживается в MariaDB и MySQL. В других базах данных x ^ y ^ ... ^ z
преобразуется в эквивалент:
(x OR y OR ... OR z) AND
1=(
(CASE WHEN x THEN 1 ELSE 0 END) +
(CASE WHEN y THEN 1 ELSE 0 END) +
...
(CASE WHEN z THEN 1 ELSE 0 END) +
)
Методы, которые не возвращают QuerySet
¶
Следующие методы QuerySet
выполняют QuerySet
и возвращают что-то отличное от QuerySet
.
Эти методы не используют кеш (смотрите Кэширование и QuerySet). Скорее, они запрашивают базу данных каждый раз, когда их вызывают.
Поскольку эти методы оценивают QuerySet, они являются блокирующими вызовами, и поэтому их основные (синхронные) версии не могут быть вызваны из асинхронного кода. По этой причине каждый из них имеет соответствующую асинхронную версию с префиксом a
- например, вместо get(…)
вы можете await aget(…)
.
Обычно нет никакой разницы в поведении, кроме их асинхронной природы, но любые различия отмечены ниже рядом с каждым методом.
Были добавлены асинхронные версии каждого метода с префиксом a
.
get()
¶
-
get
(*args, **kwargs)¶
-
aget
(*args, **kwargs)¶
Асинхронная версия: aget()
Возвращает объект, соответствующий заданным параметрам поиска, который должен быть в формате, описанном в Поиск по полям. Вы должны использовать поиски, которые гарантированно уникальны, такие как первичный ключ или поля в ограничении уникальности. Например:
Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))
Если вы ожидаете, что набор запросов уже вернет одну строку, вы можете использовать get()
без каких-либо аргументов, чтобы вернуть объект для этой строки:
Entry.objects.filter(pk=1).get()
Если get()
не находит никаких объектов, возникает исключение Model.DoesNotExist
:
Entry.objects.get(id=-999) # raises Entry.DoesNotExist
Если get()
находит более одного объекта, он вызывает исключение Model.MultipleObjectsReturned
:
Entry.objects.get(name='A Duplicated Name') # raises Entry.MultipleObjectsReturned
Оба эти класса исключений являются атрибутами класса модели и специфичны для этой модели. Если вы хотите обрабатывать такие исключения из нескольких вызовов get()
для разных моделей, вы можете использовать их общие базовые классы. Например, вы можете использовать django.core.exceptions.ObjectDoesNotExist
для обработки исключений DoesNotExist
из нескольких моделей:
from django.core.exceptions import ObjectDoesNotExist
try:
blog = Blog.objects.get(id=1)
entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
print("Either the blog or entry doesn't exist.")
Был добавлен метод aget()
.
create()
¶
-
create
(**kwargs)¶
-
acreate
(*args, **kwargs)¶
Асинхронная версия: acreate()
Удобный метод для создания объекта и сохранения всего за один шаг. Таким образом:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
и:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
эквивалентны.
Параметр force_insert задокументирован в другом месте, но все это означает, что новый объект всегда будет создаваться. Обычно вам не нужно беспокоиться об этом. Однако, если ваша модель содержит заданное вами значение первичного ключа вручную, и если это значение уже существует в базе данных, вызов create()
завершится неудачно с IntegrityError
, так как первичные ключи должны быть уникальными. Будьте готовы обработать исключение, если вы используете первичные ключи вручную.
Был добавлен метод acreate()
.
get_or_create()
¶
-
get_or_create
(defaults=None, **kwargs)¶
-
aget_or_create
(defaults=None, **kwargs)¶
Asynchronous version: 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
.
Finally, a word on using get_or_create()
in Django views. Please make sure
to use it only in POST
requests unless you have a good reason not to.
GET
requests shouldn’t have any effect on data. Instead, use POST
whenever a request to a page has a side effect on your data. For more, see
Safe methods in the HTTP spec.
Предупреждение
Вы можете использовать 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
должно быть уникальным.
aget_or_create()
method was added.
update_or_create()
¶
-
update_or_create
(defaults=None, **kwargs)¶
-
aupdate_or_create
(defaults=None, **kwargs)¶
Asynchronous version: aupdate_or_create()
Удобный метод для обновления объекта с указанным kwargs
, создания нового при необходимости. defaults
- это словарь пар (поле, значение), используемых для обновления объекта. Значения в defaults
могут быть вызываемыми.
Возвращает кортеж (object, created)
, где object
является созданным или обновленным объектом, а created
является логическим значением, указывающим, был ли создан новый объект.
Метод update_or_create
пытается извлечь объект из базы данных на основе заданного kwargs
. Если совпадение найдено, оно обновляет поля, переданные в словаре defaults
.
Это просто сокращение для упрощенного кода. Например:
defaults = {'first_name': 'Bob'}
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {'first_name': 'John', 'last_name': 'Lennon'}
new_values.update(defaults)
obj = Person(**new_values)
obj.save()
Эта модель становится довольно громоздкой, так как количество полей в модели увеличивается. Приведенный выше пример можно переписать с помощью update_or_create()
, например так:
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
For a detailed description of how names passed in kwargs
are resolved, see
get_or_create()
.
Как описано выше в get_or_create()
, этот метод подвержен гоночному состоянию, которое может привести к одновременной вставке нескольких строк, если уникальность не обеспечивается на уровне базы данных.
Также как get_or_create()
и create()
, если вы используете указанные вручную первичные ключи, и объект должен быть создан, но ключ уже существует в базе данных, то это вызовет IntegrityError
.
aupdate_or_create()
method was added.
В старых версиях update_or_create()
не указывал update_fields
при вызове Model.save()
.
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()
This method inserts the provided list of objects into the database in an efficient manner (generally only 1 query, no matter how many objects there are), and returns created objects as a list, in the same order as provided:
>>> objs = Entry.objects.bulk_create([
... Entry(headline='This is a test'),
... Entry(headline='This is only a test'),
... ])
Это имеет ряд предостережений, хотя:
Метод
save()
модели вызываться не будет, а сигналыpre_save
иpost_save
не будут отправлены.Он не работает с дочерними моделями в сценарии наследования нескольких таблиц.
If the model’s primary key is an
AutoField
, the primary key attribute can only be retrieved on certain databases (currently PostgreSQL, MariaDB 10.5+, and SQLite 3.35+). On other databases, it will not be set.Это не работает с отношениями «многие ко многим».
Он бросает
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 переменных на запрос.
On databases that support it (all but Oracle), setting the ignore_conflicts
parameter to True
tells the database to ignore failure to insert any rows
that fail constraints such as duplicate unique values.
В базах данных, которые поддерживают это (все, кроме Oracle и SQLite < 3.24), установка параметра update_conflicts
в значение True
указывает базе данных обновить update_fields
, когда вставка строки не удалась из-за конфликтов. В PostgreSQL и SQLite, в дополнение к update_fields
, необходимо предоставить список unique_fields
, которые могут быть в конфликте.
Enabling the ignore_conflicts
or update_conflicts
parameter disable
setting the primary key on each model instance (if the database normally
support it).
Предупреждение
В MySQL и MariaDB установка параметра ignore_conflicts
на True
превращает определенные типы ошибок, кроме повторяющегося ключа, в предупреждения. Даже в строгом режиме. Например: недопустимые значения или нарушения, не допускающие значения NULL. Дополнительную информацию смотрите в документации MySQL и документации MariaDB.
Параметры update_conflicts
, update_fields
и unique_fields
были добавлены для поддержки обновления полей, когда вставка строки не удается из-за конфликта.
abulk_create()
method was added.
bulk_update()
¶
-
bulk_update
(objs, fields, batch_size=None)¶
-
abulk_update
(objs, fields, batch_size=None)¶
Асинхронная версия: abulk_update()
This method efficiently updates the given fields on the provided model instances, generally with one query, and returns the number of objects updated:
>>> 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
. - Обновление полей, определенных в предках наследования нескольких таблиц, повлечет за собой дополнительный запрос для предка.
- When an individual batch contains duplicates, only the first instance in that batch will result in an update.
- Количество обновленных объектов, возвращаемых функцией, может быть меньше, чем количество переданных объектов. Это может быть вызвано дублированием переданных объектов, которые обновляются в одной и той же партии, или условиями гонки, когда объекты больше не присутствуют в базе данных.
Параметр batch_size
определяет, сколько объектов сохраняется в одном запросе. По умолчанию обновляются все объекты в одном пакете, кроме SQLite и Oracle, которые имеют ограничения по количеству переменных, используемых в запросе.
abulk_update()
method was added.
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()
будет использовать эту длину, а не выполнять дополнительный запрос к базе данных.
Был добавлен метод acount()
.
in_bulk()
¶
-
in_bulk
(id_list=None, *, field_name='pk')¶
-
ain_bulk
(id_list=None, *, field_name='pk')¶
Асинхронная версия: ain_bulk()
Takes a list of field values (id_list
) and the field_name
for those
values, and returns a dictionary mapping each value to an instance of the
object with the given field value. No
django.core.exceptions.ObjectDoesNotExist
exceptions will ever be raised
by in_bulk
; that is, any id_list
value not matching any instance will
simply be ignored. If id_list
isn’t provided, all objects
in the queryset are returned. field_name
must be a unique field or a
distinct field (if there’s only one field specified in distinct()
).
field_name
defaults to the primary key.
Пример:
>>> 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()
пустой список, вы получите пустой словарь.
Был добавлен метод ain_bulk()
.
iterator()
¶
-
iterator
(chunk_size=None)¶
-
aiterator
(chunk_size=None)¶
Асинхронная версия: aiterator()
Оценивает QuerySet
(выполняя запрос) и возвращает итератор (см. PEP 234) по результатам, или асинхронный итератор (см. PEP 492), если вы вызываете его асинхронную версию aiterator
.
A QuerySet
typically caches its results internally so that repeated
evaluations do not result in additional queries. In contrast, iterator()
will read results directly, without doing any caching at the QuerySet
level
(internally, the default iterator calls iterator()
and caches the return
value). For a QuerySet
which returns a large number of objects that you
only need to access once, this can result in better performance and a
significant reduction in memory.
Обратите внимание, что использование iterator()
на QuerySet
, который уже был оценен, заставит его вычислять снова, повторяя запрос.
iterator()
совместим с предыдущими вызовами prefetch_related()
при условии, что задано chunk_size
. Большие значения потребуют меньшего количества запросов для выполнения предварительной выборки за счет большего использования памяти.
Примечание
aiterator()
не совместим с предыдущими вызовами prefetch_related()
.
В некоторых базах данных (например, Oracle, SQLite) максимальное количество терминов в предложении SQL IN
может быть ограничено. Поэтому следует использовать значения ниже этого предела. (В частности, при предварительной выборке по двум или более отношениям, chunk_size
должно быть достаточно маленьким, чтобы ожидаемое количество результатов для каждого предварительно выбранного отношения все еще было ниже предела).
До тех пор, пока QuerySet не выполняет предварительную выборку связанных объектов, отсутствие значения для chunk_size
приведет к тому, что Django будет использовать неявное значение по умолчанию 2000.
В зависимости от серверной части базы данных результаты запроса будут загружаться одновременно или передаваться из базы данных с использованием серверных курсоров.
Support for prefetching related objects was added to iterator()
.
Был добавлен метод aiterator()
.
Не рекомендуется, начиная с версии 4.1: Использование iterator()
в наборе запросов, который осуществляет предварительную выборку связанных объектов без предоставления chunk_size
, является устаревшим. В Django 5.0 будет возникать исключение.
С серверными курсорами¶
Oracle и PostgreSQL используют серверные курсоры для потоковой передачи результатов из базы данных без загрузки всего набора результатов в память.
Драйвер базы данных Oracle всегда использует серверные курсоры.
В случае серверных курсоров параметр chunk_size
указывает количество результатов, которые необходимо кэшировать на уровне драйвера базы данных. Выборка больших кусков уменьшает количество циклов между драйвером базы данных и базой данных за счет памяти.
В PostgreSQL серверные курсоры будут использоваться, только если для параметра DISABLE_SERVER_SIDE_CURSORS
установлено значение False
. Прочитайте Объединение транзакций и курсоры на стороне сервера, если вы используете пул соединений, настроенный в режиме пула транзакций. Когда серверные курсоры отключены, поведение аналогично базам данных, которые не поддерживают серверные курсоры.
Без серверных курсоров¶
MySQL не поддерживает потоковые результаты, поэтому драйвер базы данных Python загружает весь набор результатов в память. Затем результирующий набор преобразуется в объекты строк Python с помощью адаптера базы данных с помощью метода fetchmany()
, определенного в PEP 249.
SQLite может получать результаты в пакетах, используя fetchmany()
, но поскольку SQLite не обеспечивает изоляцию между запросами в соединении, будьте осторожны при записи в таблицу, для которой выполняется итерация. Смотрите Изоляция при использовании QuerySet.iterator() для получения дополнительной информации.
Параметр chunk_size
управляет размером пакетов, которые Django извлекает из драйвера базы данных. Большие пакеты уменьшают накладные расходы на связь с драйвером базы данных за счет небольшого увеличения потребления памяти.
So long as the QuerySet does not prefetch any related objects, providing no
value for chunk_size
will result in Django using an implicit default of
2000, a value derived from a calculation on the psycopg mailing list:
Предполагая, что строки из 10-20 столбцов содержат смесь текстовых и числовых данных, 2000 будет собирать данные размером менее 100 КБ, что представляется хорошим компромиссом между количеством переданных строк и данными, отброшенными, если цикл завершается досрочно.
latest()
¶
-
latest
(*fields)¶
-
alatest
(*fields)¶
Асинхронная версия: alatest()
Возвращает последний объект в таблице на основе заданных полей.
Этот пример возвращает последний Entry
в таблице, согласно полю pub_date
:
Entry.objects.latest('pub_date')
Вы также можете выбрать последнюю версию на основе нескольких полей. Например, чтобы выбрать Entry
с самым ранним expire_date
, когда две записи имеют одинаковое pub_date
:
Entry.objects.latest('pub_date', '-expire_date')
Отрицательный знак в '-expire_date'
означает сортировку expire_date
в обратном порядке. Поскольку latest()
получает последний результат, выбирается Entry
с самым ранним expire_date
.
Если ваша модель Meta указывает get_latest_by
, вы можете опустить любые аргументы для earliest()
или latest()
. Поля, указанные в get_latest_by
, будут использоваться по умолчанию.
Например get()
, earliest()
и latest()
вызывают DoesNotExist
, если нет объекта с данными параметрами.
Обратите внимание, что earliest()
и latest()
существуют исключительно для удобства и читабельности.
earliest()
и latest()
могут возвращать экземпляры с нулевыми датами.
Поскольку порядок делегирования в базе данных, результаты в полях, которые допускают нулевые значения, могут быть упорядочены по-разному, если вы используете разные базы данных. Например, PostgreSQL и MySQL сортируют нулевые значения, как будто они выше ненулевых значений, в то время как SQLite делает обратное.
Вы можете отфильтровать нулевые значения:
Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
Был добавлен метод alatest()
.
earliest()
¶
-
earliest
(*fields)¶
-
aearliest
(*fields)¶
Асинхронная версия: aearliest()
Работает также как и latest()
за исключением изменения направления.
Был добавлен метод aearliest()
.
first()
¶
-
first
()¶
-
afirst
()¶
Асинхронная версия: afirst()
Возвращает первый объект, соответствующий запросу, или None
, если нет соответствующего объекта. Если QuerySet
не имеет определенного порядка, то набор запросов автоматически упорядочивается по первичному ключу. Это может повлиять на результаты агрегации, как описано в Interaction with 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
Был добавлен метод afirst()
.
last()
¶
-
last
()¶
-
alast
()¶
Асинхронная версия: alast()
Работает как first()
, но возвращает последний объект в наборе запросов.
Был добавлен метод alast()
.
aggregate()
¶
-
aggregate
(*args, **kwargs)¶
-
aaggregate
(*args, **kwargs)¶
Асинхронная версия: aaggregate()
Возвращает словарь агрегированных значений (средние, суммы и т.д.), рассчитанных по QuerySet
. Каждый аргумент aggregate()
указывает значение, которое будет включено в возвращаемый словарь.
Функции агрегации, предоставляемые Django, описаны в Функции агрегации ниже. Поскольку агрегаты также являются выражениями запросов, вы можете комбинировать агрегаты с другими агрегатами или значениями для создания сложных агрегатов.
Агрегаты, указанные с использованием аргументов ключевого слова, будут использовать ключевое слово в качестве имени для аннотации. Для анонимных аргументов будет создано имя, основанное на имени агрегирующей функции и агрегируемого поля модели. Сложные агрегаты не могут использовать анонимные аргументы и должны указывать ключевое слово аргумент в качестве псевдонима.
Например, когда вы работаете с записями в блоге, вы можете узнать количество авторов, которые предоставили записи в блоге:
>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
Используя аргумент ключевого слова для указания функции агрегирования, вы можете контролировать имя возвращаемого значения агрегации:
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}
Подробное обсуждение агрегации смотрите в руководство по агрегации.
aaggregate()
method was added.
exists()
¶
-
exists
()¶
-
aexists
()¶
Асинхронная версия: aexists()
Возвращает True
, если QuerySet
содержит какие-либо результаты, и False
, если нет. Он пытается выполнить запрос самым простым и быстрым способом, но он выполняет почти тот же запрос, что и обычный QuerySet
.
exists()
is useful for searches relating to the existence of
any objects in a QuerySet
, particularly in the context of a large
QuerySet
.
To find whether a queryset contains any items:
if some_queryset.exists():
print("There is at least one object in some_queryset")
Который будет быстрее, чем
if some_queryset:
print("There is at least one object in some_queryset")
… но не в значительной степени (следовательно, для повышения эффективности требуется большой набор запросов).
Кроме того, если some_queryset
еще не был проанализирован, но вы знаете, что это произойдет в какой-то момент, то использование some_queryset.exists()
сделает более общую работу (один запрос для проверки существования плюс дополнительный для последующего извлечения результатов), а не просто bool(some_queryset)
, который извлекает результаты и затем проверяет, были ли какие-либо возвращены.
Был добавлен метод aexists()
.
contains()
¶
-
contains
(obj)¶
-
acontains
(obj)¶
Асинхронная версия: acontains()
Returns True
if the QuerySet
contains obj
, and False
if
not. This tries to perform the query in the simplest and fastest way possible.
contains()
is useful for checking an object membership in a
QuerySet
, particularly in the context of a large QuerySet
.
To check whether a queryset contains a specific item:
if some_queryset.contains(obj):
print('Entry contained in queryset')
This will be faster than the following which requires evaluating and iterating through the entire queryset:
if obj in some_queryset:
print('Entry contained in queryset')
Like exists()
, if some_queryset
has not yet been evaluated, but you
know that it will be at some point, then using some_queryset.contains(obj)
will make an additional database query, generally resulting in slower overall
performance.
Был добавлен метод acontains()
.
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()
Был добавлен метод aupdate()
.
Сортировка набора¶
Связь order_by()
с update()
поддерживается только в MariaDB и MySQL и игнорируется для других баз данных. Это полезно для обновления уникального поля в указанном порядке без конфликтов. Например:
Entry.objects.order_by('-number').update(number=F('number') + 1)
Примечание
order_by()
clause will be ignored if it contains annotations, inherited
fields, or lookups spanning relations.
delete()
¶
-
delete
()¶
-
adelete
()¶
Асинхронная версия: adelete()
Выполняет запрос на удаление SQL для всех строк в QuerySet
и возвращает количество удаленных объектов и словарь с количеством удалений на тип объекта.
delete()
применяется мгновенно. Вы не можете вызвать delete()
для QuerySet
, у которого был взят фрагмент или который больше не может быть отфильтрован.
Например, чтобы удалить все записи в определенном блоге:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})
По умолчанию класс Django ForeignKey
эмулирует ограничение SQL ON DELETE CASCADE
- другими словами, любые объекты с внешними ключами, указывающими на объекты, которые будут удалены, будут удалены вместе с ними. Например:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})
Это каскадное поведение настраивается с помощью аргумента on_delete
для ForeignKey
.
Метод delete()
выполняет массовое удаление и не вызывает никаких методов delete()
в ваших моделях. Однако он генерирует сигналы pre_delete
и post_delete
для всех удаленных объектов (включая каскадные удаления).
Django должен извлекать объекты в память для отправки сигналов и обработки каскадов. Однако, если нет каскадов и нет сигналов, тогда Django может использовать ускоренный путь и удалять объекты без загрузки в память. Для больших удалений это может привести к значительному сокращению использования памяти. Количество выполненных запросов также может быть уменьшено.
Внешние ключи, для которых установлено on_delete
DO_NOTHING
, не мешают использовать быстрый путь при удалении.
Обратите внимание, что запросы, сгенерированные при удалении объекта, являются деталями реализации, которые могут быть изменены.
Был добавлен метод adelete()
.
as_manager()
¶
-
classmethod
as_manager
()¶
Метод класса, который возвращает экземпляр Manager
с копией методов QuerySet
. Смотрите Создание менеджера с помощью методов QuerySet для более подробной информации.
Обратите внимание, что в отличие от других записей в этом разделе, эта не имеет асинхронного варианта, поскольку она не выполняет запрос.
explain()
¶
-
explain
(format=None, **options)¶
-
aexplain
(format=None, **options)¶
Асинхронная версия: aexplain()
Возвращает строку плана выполнения QuerySet
, в которой подробно описывается, как база данных будет выполнять запрос, включая любые индексы или объединения, которые будут использоваться. Знание этих деталей может помочь вам повысить производительность медленных запросов.
Например, при использовании PostgreSQL:
>>> print(Blog.objects.filter(title='My Blog').explain())
Seq Scan on blog (cost=0.00..35.50 rows=10 width=12)
Filter: (title = 'My Blog'::bpchar)
Вывод значительно различается между базами данных.
explain()
поддерживается всеми встроенными базами данных базы данных, кроме Oracle, потому что реализация там не проста.
Параметр format
изменяет формат вывода по умолчанию для баз данных, который обычно является текстовым. PostgreSQL поддерживает форматы 'TEXT'
, 'JSON'
, 'YAML'
и 'XML'
. MariaDB и MySQL поддерживают форматы 'TEXT'
(также называемые 'TRADITIONAL'
) и 'JSON'
. MySQL 8.0.16+ также поддерживает улучшенный формат 'TREE'
, который похож на вывод 'TEXT'
PostgreSQL и используется по умолчанию, если поддерживается.
Некоторые базы данных принимают флаги, которые могут возвращать больше информации о запросе. Передайте эти флаги в качестве ключевых аргументов. Например, при использовании PostgreSQL:
>>> print(Blog.objects.filter(title='My Blog').explain(verbose=True, analyze=True))
Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
Output: id, title
Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms
В некоторых базах данных флаги могут привести к выполнению запроса, что может отрицательно повлиять на вашу базу данных. Например, флаг ANALYZE
, поддерживаемый MariaDB, MySQL 8.0.18+ и PostgreSQL, может привести к изменениям данных, если есть триггеры или если вызывается функция, даже для запроса SELECT
.
Был добавлен метод aexplain()
.
Поиск Field
¶
Поиск по полю - это то, как вы определяете содержание предложения SQL WHERE
. Они указываются в качестве аргументов ключевых слов для методов QuerySet
filter()
, exclude()
и get()
.
Для ознакомления смотрите документация по моделям и запросам к базе данных.
Встроенные в Django поиски перечислены ниже. Также возможно написать собственные поиски для полей модели.
Для удобства, когда не указан тип поиска (как в Entry.objects.get(id=14)
), предполагается, что тип поиска exact
.
exact
¶
Точное совпадение. Если значение, предоставленное для сравнения, равно None
, оно будет интерпретировано как SQL NULL
(подробнее см. isnull
).
Примеры:
Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)
SQL-эквивалент:
SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;
MySQL сравнения
В MySQL настройка «collation» таблицы базы данных определяет, являются ли exact
сравнения чувствительными к регистру. Это настройка базы данных, а не настройка Django. Можно настроить ваши таблицы MySQL для использования чувствительных к регистру сравнений, но здесь есть некоторые компромиссы. Для получения дополнительной информации об этом смотрите раздел collation в документации базы данных.
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
для принудительного выполнения первого запроса. Без него будет выполнен вложенный запрос, потому что `` QuerySet`` - ленивые.
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';
Вообще говоря, вы не можете смешивать даты и время.
date
¶
Для полей даты и времени преобразует значение как дату. Позволяет цепочки дополнительных поисков по полям. Принимает значение даты.
Пример:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)
Когда USE_TZ
равно True
, поля преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
year
¶
Для полей даты и даты и времени точное совпадение года. Позволяет цепочки дополнительных поисков по полям. Принимает целое число - год.
Пример:
Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)
SQL-эквивалент:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
iso_year
¶
Для полей даты и даты и времени точно указан год недели с номером нумерации ISO 8601. Позволяет цепочки дополнительных полевых поисков. Принимает целое число - год.
Пример:
Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
month
¶
Для полей даты и даты и времени точное совпадение месяцев. Позволяет цепочки дополнительных поисков по полям. Принимает целое число от 1 (январь) до 12 (декабрь).
Пример:
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
day
¶
Для полей даты и даты и времени - точное совпадение дня. Позволяет цепочки дополнительных поисков по полям. Принимает целое число - день.
Пример:
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date в третий день месяца, например 3 января, 3 июля и т.д.
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
week
¶
Для полей даты и даты и времени возвращает номер недели (1-52 или 53) в соответствии с ISO-8601 <https://en.wikipedia.org/wiki/ISO-8601> _, то есть недели, начинающиеся в понедельник и первая неделя содержит первый четверг года.
Пример:
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
week_day
¶
Для полей даты и даты и времени соответствует «день недели». Позволяет цепочки дополнительных поисков.
Принимает целочисленное значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).
Пример:
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date
, которая выпадает на понедельник (2-ой день недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются, причем день 1 - воскресенье, а день 7 - суббота.
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
iso_week_day
¶
Для полей даты и даты-времени точный день недели соответствует ISO 8601. Позволяет цепочки дополнительных поисков.
Принимает целочисленное значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).
Пример:
Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)
(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date
, которая выпадает на понедельник (1-й день недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются, причем день 1 - понедельник, а день 7 - воскресенье.
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
quarter
¶
Для полей даты и даты и времени соответствующий квартал года. Позволяет цепочки дополнительных поисков. Принимает целое значение от 1 до 4, представляющее квартал года.
Пример получения записей во втором квартале (с 1 апреля по 30 июня):
Entry.objects.filter(pub_date__quarter=2)
(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
time
¶
Для полей даты и времени преобразует значение как время. Позволяет цепочки дополнительных поисков. Принимает значение datetime.time
.
Пример:
Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)
Когда USE_TZ
равно True
, поля преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
hour
¶
Для полей даты и времени точное совпадение часов. Позволяет цепочки дополнительных поисков. Принимает целое число от 0 до 23.
Пример:
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
minute
¶
Для полей даты и времени, точное совпадение минут. Позволяет цепочки дополнительных поисков. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
second
¶
Для полей даты и времени точное совпадение секунд. Позволяет цепочки дополнительных поисков. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)
SQL-эквивалент:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(Точный синтаксис SQL варьируется для каждого механизма базы данных.)
Когда USE_TZ
равно True
, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.
isnull
¶
Принимает True
или False
, которые соответствуют SQL-запросам IS NULL
и IS NOT NULL
, соответственно.
Пример:
Entry.objects.filter(pub_date__isnull=True)
SQL-эквивалент:
SELECT ... WHERE pub_date IS NULL;
regex
¶
Чувствительное к регистру совпадение регулярного выражения.
Синтаксис регулярного выражения - это используемый серверный компонент базы данных. В случае SQLite, который не имеет встроенной поддержки регулярных выражений, эта функция обеспечивается пользовательской функцией REGEXP (Python), поэтому синтаксис регулярного выражения является синтаксисом модуля 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 can’t handle aggregation on date/time fields out of the box.
This is because there are no native date/time fields in SQLite and Django
currently emulates these features using a text field. Attempts to use
aggregation on date/time fields in SQLite will raise NotSupportedError
.
Примечание
Aggregation functions return None
when used with an empty
QuerySet
. For example, the Sum
aggregation function returns None
instead of 0
if the QuerySet
contains no entries. To return another
value instead, pass a value to the default
argument. An exception is
Count
, which does return 0
if the QuerySet
is empty. Count
does not support the default
argument.
Все агрегаты имеют следующие общие параметры:
expressions
¶
Strings that reference fields on the model, transforms of the field, or query 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
, если он указан
-
distinct
¶ Optional. If
distinct=True
,Avg
returns the mean value of unique values. This is the SQL equivalent ofAVG(DISTINCT <field>)
. The default value isFalse
.
- Псевдоним по умолчанию:
Count
¶
-
class
Count
(expression, distinct=False, filter=None, **extra)[исходный код]¶ Возвращает количество объектов, связанных через предоставленное выражение.
- Псевдоним по умолчанию:
<field>__count
- Тип возврата: `` int``
-
distinct
¶ Optional. If
distinct=True
, the count will only include unique instances. This is the SQL equivalent ofCOUNT(DISTINCT <field>)
. The default value isFalse
.
Примечание
The
default
argument is not supported.- Псевдоним по умолчанию:
Max
¶
-
class
Max
(expression, output_field=None, filter=None, default=None, **extra)[исходный код]¶ Возвращает максимальное значение данного выражения.
- Псевдоним по умолчанию:
<field>__max
- Тип возвращаемого значения: такой же, как у поля ввода, или
output_field
, если указано
- Псевдоним по умолчанию:
Min
¶
-
class
Min
(expression, output_field=None, filter=None, default=None, **extra)[исходный код]¶ Возвращает минимальное значение данного выражения.
- Псевдоним по умолчанию:
<field>__min
- Тип возвращаемого значения: такой же, как у поля ввода, или
output_field
, если указано
- Псевдоним по умолчанию:
StdDev
¶
-
class
StdDev
(expression, output_field=None, sample=False, filter=None, default=None, **extra)[исходный код]¶ Возвращает стандартное отклонение данных в предоставленном выражении.
- Псевдоним по умолчанию:
<field>__stddev
- Тип возвращаемого значения:
float
, если на входеint
, в остальном то же самое, что и поле ввода, илиoutput_field
, если он указан
-
sample
¶ Optional. By default,
StdDev
returns the population standard deviation. However, ifsample=True
, the return value will be the sample standard deviation.
- Псевдоним по умолчанию:
Sum
¶
-
class
Sum
(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[исходный код]¶ Вычисляет сумму всех значений данного выражения.
- Псевдоним по умолчанию:
<field>__sum
- Тип возвращаемого значения: такой же, как у поля ввода, или
output_field
, если указано
-
distinct
¶ Optional. If
distinct=True
,Sum
returns the sum of unique values. This is the SQL equivalent ofSUM(DISTINCT <field>)
. The default value isFalse
.
- Псевдоним по умолчанию:
Variance
¶
-
class
Variance
(expression, output_field=None, sample=False, filter=None, default=None, **extra)[исходный код]¶ Возвращает дисперсию данных в предоставленном выражении.
- Псевдоним по умолчанию:
<field>__variance
- Тип возвращаемого значения:
float
, если на входеint
, в остальном то же самое, что и поле ввода, илиoutput_field
, если он указан
-
sample
¶ Optional. By default,
Variance
returns the population variance. However, ifsample=True
, the return value will be the sample variance.
- Псевдоним по умолчанию: