Справочник по API QuerySet
¶
Этот документ описывает детали API QuerySet
. Он основан на материале, представленном в руководствах модель и запросы к базе данных, так что вы, вероятно, захотите прочитать и понять эти документы, прежде чем читать этот.
В этом справочнике мы будем использовать пример моделей Weblog’а, представленный в руководстве по запросам к базе данных.
Когда вычисляется QuerySet
¶
Внутренне QuerySet
может быть создан, отфильтрован, нарезан и, как правило, передан без фактического запроса к базе данных. На самом деле никаких действий с базой данных не происходит, пока вы не сделаете что-то для оценки набора запросов.
Вы можете вычислить QuerySet
следующими способами:
Итерация.
QuerySet
является итеративным, и он выполняет свой запрос к базе данных при первой итерации по нему. Например, это напечатает заголовок всех записей в базе данных:for e in Entry.objects.all(): print(e.headline)
Примечание: не используйте это, если все, что вы хотите сделать, это определить, существует ли хотя бы один результат. Более эффективно использовать
exists()
.Срезы. Как объяснено в Ограничение 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
возвращают новые наборы запросов. Эти методы подробно описаны ниже в этом разделе.Класс
QuerySet
имеет два открытых атрибута, которые вы можете использовать для самоанализа:-
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()
лишние выбранные поля будут игнорироваться.Вызов
only()
иdefer()
после values() не имеет смысла, поэтому это вызовет ошибкуTypeError
.Объединение преобразований и агрегирования требует использования двух вызовов
annotate()
, либо явно, либо в качестве именованных аргументов дляvalues()
. Как и выше, если преобразование зарегистрировано в соответствующем типе поля, первоеannotate()
может быть опущено, поэтому следующие примеры эквивалентны:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values( ... entry__authors__name__lower=Lower('entry__authors__name') ... ).annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate( ... entry__authors__name__lower=Lower('entry__authors__name') ... ).values('entry__authors__name__lower').annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
Это полезно, когда вы знаете, что вам понадобятся значения только из небольшого числа доступных полей, и вам не понадобятся функциональные возможности объекта экземпляра модели. Более эффективно выбирать только те поля, которые вам нужны.
Наконец, обратите внимание, что вы можете вызывать filter()
, order_by()
и т.д. после вызова values()
, это означает, что эти два вызова идентичны:
Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()
Люди, которые сделали Django, предпочитают сначала поместить все методы, влияющие на SQL, а затем (необязательно) любые методы, влияющие на вывод (такие как values()
), но это не имеет большого значения. Это ваш шанс по-настоящему выставить напоказ свой индивидуализм.
Вы также можете ссылаться на поля в связанных моделях с обратными связями через атрибуты OneToOneField
, ForeignKey
и ManyToManyField
:
>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Предупреждение
Потому что ManyToManyField
атрибуты и обратные отношения могут иметь несколько связанных строк, в том числе они могут повлиять на размер набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в ваш запрос values()
, и в этом случае будут возвращены все возможные комбинации.
Логические значения для JSONField
в SQLite
Из-за того, как SQL-функция JSON_EXTRACT
реализована в SQLite, values()
вернет 1
и 0
вместо True
и False
для преобразования ключа 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
реализована в SQLite, values_list()
будет возвращать 1
и 0
вместо True
и False
для преобразования ключа 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.
Был добавлен параметр is_dst
.
Примечание
Эта функция выполняет преобразование часового пояса непосредственно в базе данных. Как следствие, ваша база данных должна иметь возможность интерпретировать значение tzinfo.tzname(None)
. Это приводит к следующим требованиям:
- SQLite: нет требований. Преобразования выполняются в Python с помощью pytz (устанавливается при установке Django).
- PostgreSQL: никаких требований (см. Часовые пояса).
- Oracle: нет требований (см. Выбор файла часового пояса).
- MySQL: загрузить таблицы часовых поясов с помощью mysql_tzinfo_to_sql.
none()
¶
-
none
()¶
Вызов none()
создаст набор запросов, который никогда не возвращает никаких объектов, и никакой запрос не будет выполняться при доступе к результатам. Набор запросов qs.none()
является экземпляром EmptyQuerySet
.
Примеры:
>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
all()
¶
-
all
()¶
Возвращает копию текущего QuerySet
(или подкласса QuerySet
). Это может быть полезно в ситуациях, когда вы захотите передать либо менеджер модели, либо QuerySet
и выполнить дальнейшую фильтрацию по результату. После вызова all()
для любого объекта у вас обязательно будет QuerySet
для работы.
Когда QuerySet
вычисляется, он обычно кэширует свои результаты. Если данные в базе данных могли измениться после вычисления QuerySet
, вы можете получить обновленные результаты для того же запроса, вызвав all()
для ранее вычисленного QuerySet
.
union()
¶
-
union
(*other_qs, all=False)¶
Использует оператор SQL UNION
для объединения результатов двух или более QuerySet
’ов. Например:
>>> qs1.union(qs2, qs3)
Оператор UNION
выбирает только отдельные значения по умолчанию. Чтобы разрешить повторяющиеся значения, используйте аргумент all=True
.
union()
, intersection()
и difference()
возвращают экземпляры модели с типом первого QuerySet
, даже если аргументами являются QuerySet
других моделей. Передача разных моделей работает до тех пор, пока список SELECT
одинаков во всех QuerySet
(по крайней мере, типы, имена не имеют значения, если типы находятся в одном порядке). В таких случаях вы должны использовать имена столбцов из первого QuerySet
в методах QuerySet
, примененных к результирующему QuerySet
. Например:
>>> qs1 = Author.objects.values_list('name')
>>> qs2 = Entry.objects.values_list('headline')
>>> qs1.union(qs2).order_by('name')
Кроме того, только LIMIT
, OFFSET
, COUNT(*)
, ORDER BY
и указание столбцов (т.е. срезов, count()
, exists()
, order_by()
и values()
/values_list()
) разрешены в результирующем QuerySet
. Кроме того, базы данных накладывают ограничения на то, какие операции разрешены в комбинированных запросах. Например, большинство баз данных не позволяют использовать LIMIT
или OFFSET
в комбинированных запросах.
intersection()
¶
-
intersection
(*other_qs)¶
Использует оператор SQL INTERSECT
для возврата общих элементов двух или более QuerySet
’ов. Например:
>>> qs1.intersection(qs2, qs3)
Смотрите union()
для некоторых ограничений.
difference()
¶
-
difference
(*other_qs)¶
Использует оператор SQL EXCEPT
для хранения только элементов, присутствующих в QuerySet
, но не в каких-либо других QuerySet
’ах. Например:
>>> qs1.difference(qs2, qs3)
Смотрите union()
для некоторых ограничений.
extra()
¶
-
extra
(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)¶
Иногда синтаксис запроса Django сам по себе не может легко выразить сложное предложение WHERE
. Для этих крайних случаев Django предоставляет модификатор extra()
QuerySet
- ловушку для вставки определенных предложений в SQL, генерируемый QuerySet
.
Используйте этот метод в качестве крайней меры
Это старый API, который мы запретим в какой-то момент в будущем. Используйте его, только если вы не можете выразить свой запрос, используя другие методы набора запросов. Если вам нужно его использовать, пожалуйста, отправьте заявку <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")
Набор запросов с отложенными полями будет по-прежнему возвращать экземпляры модели. Каждое отложенное поле будет извлечено из базы данных, если вы получите доступ к этому полю (по одному, а не ко всем отложенным полям одновременно).
Вы можете сделать несколько вызовов 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()
, ниже) предназначены только для расширенных вариантов использования. Они обеспечивают оптимизацию, когда вы тщательно проанализировали свои запросы и точно поняли, какая информация вам нужна, и измерили, что разница между возвратом необходимых вам полей и полным набором полей для модели будет значительной.
Даже если вы думаете, что находитесь в расширенной ситуации варианта использования, используйте defer() только тогда, когда вы не можете во время загрузки набора запросов определить, нужны ли вам дополнительные поля или нет. Если вы часто загружаете и используете определенное подмножество ваших данных, лучший выбор, который вы можете сделать, - это нормализовать ваши модели и поместить незагруженные данные в отдельную модель (и таблицу базы данных). Если столбцы должны по какой-то причине оставаться в одной таблице, создайте модель с Meta.managed=False
(смотрите документацию Управляемый атрибут
) содержит только те поля, которые вы обычно должны загрузить и использовать там, где вы могли бы иначе вызвать defer()
. Это делает ваш код более понятным для читателя, немного быстрее и потребляет немного меньше памяти в процессе Python.
Например, обе эти модели используют одну и ту же базовую таблицу базы данных:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = 'app_largetable'
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = 'app_largetable'
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.all().defer('f2')
Если в неуправляемой модели необходимо дублировать многие поля, может быть лучше создать абстрактную модель с общими полями, а затем иметь неуправляемые и управляемые модели, наследуемые от абстрактной модели.
only()
¶
-
only
(*fields)¶
Метод only()
более или менее противоположен defer()
. Вы вызываете его с полями, которые не должны быть отложены при получении модели. Если у вас есть модель, в которой почти все поля необходимо отложить, использование only()
для указания дополнительного набора полей может привести к упрощению кода.
Предположим, у вас есть модель с полями name
, age
и biography
. Следующие два набора запросов одинаковы с точки зрения отложенных полей:
Person.objects.defer("age", "biography")
Person.objects.only("name")
Всякий раз, когда вы вызываете only()
, он заменяет набор полей для немедленной загрузки. Имя метода мнемоническое: только эти поля загружаются немедленно. Остальные откладываются. Таким образом, последовательные вызовы only()
приводят только к рассмотрению последних полей:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
Поскольку defer()
действует постепенно (добавляя поля в отложенный список), вы можете комбинировать вызовы only()
и defer()
, и все будет вести себя логически:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")
Все предостережения в примечании к документации defer()
относятся и к only()
. Используйте его осторожно и только после того, как исчерпаете ваши другие возможности.
Использование only()
и пропуск поля, запрошенного с использованием select_related()
, также является ошибкой.
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'))
Только в 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: ...)>, ...]>
В настоящее время бэкенды баз данных postgresql
, oracle
и mysql
поддерживают select_for_update()
. Однако MariaDB 10.3+ поддерживает только аргумент nowait
, а MySQL 8.0.1+ поддерживает аргументы nowait
, skip_locked
и of
. Аргумент no_key
поддерживается только в 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
.
Добавлен аргумент no_key
.
Аргумент of
был разрешен в MySQL 8.0.1+.
raw()
¶
-
raw
(raw_query, params=(), translations=None, using=None)¶
Принимает необработанный SQL-запрос, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet
. Этот экземпляр RawQuerySet
может быть повторен, как обычный QuerySet
, для предоставления экземпляров объекта.
Смотрите Выполнение необработанных SQL-запросов для получения дополнительной информации.
Предупреждение
raw()
всегда запускает новый запрос и не учитывает предыдущую фильтрацию. Как таковой, он обычно должен вызываться из Manager
или из свежего QuerySet
.
Значение по умолчанию аргумента params
было изменено с None
на пустой кортеж.
Операторы, которые возвращают новый 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
Методы, которые не возвращают QuerySet
¶
Следующие методы QuerySet
выполняют QuerySet
и возвращают что-то отличное от QuerySet
.
Эти методы не используют кеш (смотрите Кэширование и QuerySet). Скорее, они запрашивают базу данных каждый раз, когда их вызывают.
get()
¶
-
get
(*args, **kwargs)¶
Возвращает объект, соответствующий заданным параметрам поиска, который должен быть в формате, описанном в Поиск по полям. Вы должны использовать поиски, которые гарантированно уникальны, такие как первичный ключ или поля в ограничении уникальности. Например:
Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))
Если вы ожидаете, что набор запросов уже вернет одну строку, вы можете использовать get()
без каких-либо аргументов, чтобы вернуть объект для этой строки:
Entry.objects.filter(pk=1).get()
Если get()
не находит никаких объектов, возникает исключение Model.DoesNotExist
:
Entry.objects.get(id=-999) # raises Entry.DoesNotExist
Если get()
находит более одного объекта, он вызывает исключение Model.MultipleObjectsReturned
:
Entry.objects.get(name='A Duplicated Name') # raises Entry.MultipleObjectsReturned
Оба эти класса исключений являются атрибутами класса модели и специфичны для этой модели. Если вы хотите обрабатывать такие исключения из нескольких вызовов get()
для разных моделей, вы можете использовать их общие базовые классы. Например, вы можете использовать django.core.exceptions.ObjectDoesNotExist
для обработки исключений DoesNotExist
из нескольких моделей:
from django.core.exceptions import ObjectDoesNotExist
try:
blog = Blog.objects.get(id=1)
entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
print("Either the blog or entry doesn't exist.")
create()
¶
-
create
(**kwargs)¶
Удобный метод для создания объекта и сохранения всего за один шаг. Таким образом:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
и:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
эквивалентны.
Параметр force_insert задокументирован в другом месте, но все это означает, что новый объект всегда будет создаваться. Обычно вам не нужно беспокоиться об этом. Однако, если ваша модель содержит заданное вами значение первичного ключа вручную, и если это значение уже существует в базе данных, вызов create()
завершится неудачно с IntegrityError
, так как первичные ключи должны быть уникальными. Будьте готовы обработать исключение, если вы используете первичные ключи вручную.
get_or_create()
¶
-
get_or_create
(defaults=None, **kwargs)¶
Удобный метод для поиска объекта с указанным kwargs
(может быть пустым, если в вашей модели есть значения по умолчанию для всех полей), создавая его при необходимости.
Возвращает кортеж (object, created)
, где object
- извлеченный или созданный объект, а created
- логическое значение, указывающее, был ли создан новый объект.
Это предназначено для предотвращения создания дублирующихся объектов, когда запросы выполняются параллельно, и в качестве сокращения для упрощенного кода. Например:
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
Здесь, при одновременных запросах, могут быть сделаны многочисленные попытки сохранить Person
с одинаковыми параметрами. Чтобы избежать этого состояния гонки, приведенный выше пример можно переписать с помощью get_or_create()
, например так:
obj, created = Person.objects.get_or_create(
first_name='John',
last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)},
)
Любые ключевые аргументы, передаваемые в get_or_create()
- за исключением необязательного аргумента, называемого defaults
- будут использоваться в вызове get()
. Если объект найден, get_or_create()
возвращает кортеж этого объекта и False
.
Предупреждение
Этот метод является атомарным, предполагая, что база данных обеспечивает уникальность ключевых аргументов (смотрите unique
или unique_together
). Если поля, используемые в аргументах ключевого слова, не имеют ограничения уникальности, одновременные вызовы этого метода могут привести к вставке нескольких строк с одинаковыми параметрами.
Вы можете указать более сложные условия для извлеченного объекта, связав get_or_create()
с filter()
и используя Q objects
. Например, чтобы получить Роберта или Боба Марли, если таковой существует, и создать последний в противном случае:
from django.db.models import Q
obj, created = Person.objects.filter(
Q(first_name='Bob') | Q(first_name='Robert'),
).get_or_create(last_name='Marley', defaults={'first_name': 'Bob'})
Если найдено несколько объектов, get_or_create()
вызовет MultipleObjectsReturned
. Если объект не найден, get_or_create()
создаст и сохранит новый объект, возвращая кортеж из нового объекта и True
. Новый объект будет создан примерно согласно этому алгоритму:
params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
По-английски это означает, что начинать нужно с любого не ключевого аргумента 'defaults'
, который не содержит двойного подчеркивания (что указывает на неточный поиск). Затем добавьте содержимое defaults
, переопределив любые ключи, если необходимо, и используйте результат в качестве аргументов ключевого слова для класса модели. Если в defaults
есть какие-либо вызываемые элементы, выполните их. Как уже упоминалось выше, это упрощение алгоритма, который используется, но он содержит все соответствующие детали. Внутренняя реализация имеет больше проверок ошибок, чем эта, и обрабатывает некоторые дополнительные граничные условия; если вам интересно, прочитайте код.
Если у вас есть поле с именем defaults
и вы хотите использовать его для точного поиска в get_or_create()
, просто используйте 'defaults__exact'
, например, так:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
Метод get_or_create()
имеет схожее поведение ошибки с create()
, когда вы используете указанные вручную первичные ключи. Если объект должен быть создан, а ключ уже существует в базе данных, будет вызвано IntegrityError
.
Наконец, слово об использовании get_or_create()
в представлениях Django. Обязательно используйте его только в запросах POST
, если у вас нет веских причин не делать этого. Запросы GET
не должны влиять на данные. Вместо этого используйте POST
всякий раз, когда запрос страницы оказывает побочный эффект на ваши данные. Для получения дополнительной информации смотрите Безопасные методы в спецификации HTTP.
Предупреждение
Вы можете использовать get_or_create()
через ManyToManyField
атрибуты и обратные отношения. В этом случае вы будете ограничивать запросы в контексте этого отношения. Это может привести к некоторым проблемам с целостностью, если вы не используете его постоянно.
Имея следующие модели:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
Вы можете использовать get_or_create()
через поле глав книги, но оно извлекается только внутри контекста этой книги:
>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError
Это происходит потому, что он пытается получить или создать «Главу 1» через книгу «Улисс», но не может сделать ни одну из них: отношение не может извлечь эту главу, потому что оно не связано с этой книгой, но он также не может создать его, потому что поле title
должно быть уникальным.
update_or_create()
¶
-
update_or_create
(defaults=None, **kwargs)¶
Удобный метод для обновления объекта с указанным 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
.
bulk_create()
¶
-
bulk_create
(objs, batch_size=None, ignore_conflicts=False)¶
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
не будут отправлены.Он не работает с дочерними моделями в сценарии наследования нескольких таблиц.
Если первичным ключом модели является
AutoField
, атрибут первичного ключа можно получить только в определенных базах данных (в настоящее время PostgreSQL и MariaDB 10.5+). На других базах данных он не будет установлен.Это не работает с отношениями «многие ко многим».
Он бросает
objs
в список, который полностью выполняетobjs
, если это генератор. Приведение позволяет проверять все объекты, так что любые объекты с вручную установленным первичным ключом могут быть вставлены первыми. Если вы хотите вставить объекты в пакет без одновременной оценки всего генератора, вы можете использовать эту технику, если у объектов нет установленных первичных ключей вручную:from itertools import islice batch_size = 100 objs = (Entry(headline='Test %s' % i) for i in range(1000)) while True: batch = list(islice(objs, batch_size)) if not batch: break Entry.objects.bulk_create(batch, batch_size)
Параметр batch_size
контролирует, сколько объектов создается в одном запросе. По умолчанию все объекты создаются в одном пакете, за исключением SQLite, где по умолчанию используется не более 999 переменных на запрос.
В базах данных, которые это поддерживают (все, кроме Oracle), установка параметра ignore_conflicts
в True
указывает базе данных игнорировать сбой при вставке любых строк, которые не соответствуют ограничениям, таким как дублирующиеся уникальные значения. Включение этого параметра отключает установку первичного ключа для каждого экземпляра модели (если база данных обычно его поддерживает).
Предупреждение
В MySQL и MariaDB установка параметра ignore_conflicts
на True
превращает определенные типы ошибок, кроме повторяющегося ключа, в предупреждения. Даже в строгом режиме. Например: недопустимые значения или нарушения, не допускающие значения NULL. Дополнительную информацию смотрите в документации MySQL и документации MariaDB.
Добавлена поддержка извлечения атрибутов первичного ключа на MariaDB 10.5+.
bulk_update()
¶
-
bulk_update
(objs, fields, batch_size=None)¶
Этот метод эффективно обновляет данные поля в предоставленных экземплярах модели, обычно одним запросом:
>>> 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'])
QuerySet.update()
используется для сохранения изменений, поэтому это более эффективно, чем перебирать список моделей и вызывать save()
для каждой из них, но имеет несколько предостережений:
- Вы не можете обновить первичный ключ модели.
- Метод
save()
каждой модели не вызывается, и сигналыpre_save
иpost_save
не отправлено. - При обновлении большого количества столбцов в большом количестве строк сгенерированный SQL может быть очень большим. Избегайте этого, указав подходящий
batch_size
. - Обновление полей, определенных в предках наследования нескольких таблиц, повлечет за собой дополнительный запрос для предка.
- Если отдельный пакет содержит дубликаты, только первый экземпляр в этом пакете приведет к обновлению.
Параметр batch_size
определяет, сколько объектов сохраняется в одном запросе. По умолчанию обновляются все объекты в одном пакете, кроме SQLite и Oracle, которые имеют ограничения по количеству переменных, используемых в запросе.
count()
¶
-
count
()¶
Возвращает целое число, представляющее количество объектов в базе данных, соответствующих QuerySet
.
Пример:
# Returns the total number of entries in the database.
Entry.objects.count()
# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()
Вызов count()
выполняет SELECT COUNT (*)
за кулисами, поэтому вы всегда должны использовать count()
вместо того, чтобы загружать всю запись в объекты Python и вызывать len()
на результат (если вам все равно не нужно загружать объекты в память, в этом случае len()
будет быстрее).
Обратите внимание, что если вы хотите подсчитать количество элементов в QuerySet
и также извлекаете из него экземпляры модели (например, путем итерации по нему), возможно, более эффективно использовать len(queryset)
, который не вызывает дополнительный запрос к базе данных, как count()
.
Если набор запросов уже был полностью получен, count()
будет использовать эту длину, а не выполнять дополнительный запрос к базе данных.
in_bulk()
¶
-
in_bulk
(id_list=None, *, field_name='pk')¶
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()
пустой список, вы получите пустой словарь.
Разрешено использование отдельного поля.
iterator()
¶
-
iterator
(chunk_size=2000)¶
Вычисляет QuerySet
(выполняя запрос) и возвращает итератор (смотрите PEP 234) по результатам. QuerySet
обычно кэширует свои результаты внутренне, так что повторные вычисления не приводят к дополнительным запросам. Напротив, iterator()
будет читать результаты напрямую, без какого-либо кэширования на уровне QuerySet
(внутренне, итератор по умолчанию вызывает iterator()
и кэширует возвращаемое значение). Для QuerySet
, который возвращает большое количество объектов, к которым вам нужно получить доступ только один раз, это может привести к повышению производительности и значительному сокращению памяти.
Обратите внимание, что использование iterator()
на QuerySet
, который уже был оценен, заставит его вычислять снова, повторяя запрос.
Кроме того, использование iterator()
приводит к игнорированию предыдущих вызовов prefetch_related()
, поскольку эти две оптимизации не имеют смысла вместе.
В зависимости от серверной части базы данных результаты запроса будут загружаться одновременно или передаваться из базы данных с использованием серверных курсоров.
С серверными курсорами¶
Oracle и PostgreSQL используют серверные курсоры для потоковой передачи результатов из базы данных без загрузки всего набора результатов в память.
Драйвер базы данных Oracle всегда использует серверные курсоры.
В случае серверных курсоров параметр chunk_size
указывает количество результатов, которые необходимо кэшировать на уровне драйвера базы данных. Выборка больших кусков уменьшает количество циклов между драйвером базы данных и базой данных за счет памяти.
В PostgreSQL серверные курсоры будут использоваться, только если для параметра DISABLE_SERVER_SIDE_CURSORS
установлено значение False
. Прочитайте Объединение транзакций и курсоры на стороне сервера, если вы используете пул соединений, настроенный в режиме пула транзакций. Когда серверные курсоры отключены, поведение аналогично базам данных, которые не поддерживают серверные курсоры.
Без серверных курсоров¶
MySQL не поддерживает потоковые результаты, поэтому драйвер базы данных Python загружает весь набор результатов в память. Затем результирующий набор преобразуется в объекты строк Python с помощью адаптера базы данных с помощью метода fetchmany()
, определенного в PEP 249.
SQLite может получать результаты в пакетах, используя fetchmany()
, но поскольку SQLite не обеспечивает изоляцию между запросами в соединении, будьте осторожны при записи в таблицу, для которой выполняется итерация. Смотрите Изоляция при использовании QuerySet.iterator() для получения дополнительной информации.
Параметр chunk_size
управляет размером пакетов, которые Django извлекает из драйвера базы данных. Большие пакеты уменьшают накладные расходы на связь с драйвером базы данных за счет небольшого увеличения потребления памяти.
Значение по умолчанию chunk_size
, 2000, взято из вычисления в списке рассылки psycopg <https://www.postgresql.org/message-id/4D2F2C71.8080805%40dndg.it> _:
Предполагая, что строки из 10-20 столбцов содержат смесь текстовых и числовых данных, 2000 будет собирать данные размером менее 100 КБ, что представляется хорошим компромиссом между количеством переданных строк и данными, отброшенными, если цикл завершается досрочно.
latest()
¶
-
latest
(*fields)¶
Возвращает последний объект в таблице на основе заданных полей.
Этот пример возвращает последний 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')
first()
¶
-
first
()¶
Возвращает первый объект, соответствующий запросу, или 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
aggregate()
¶
-
aggregate
(*args, **kwargs)¶
Возвращает словарь агрегированных значений (средние, суммы и т.д.), рассчитанных по 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}
Подробное обсуждение агрегации смотрите в руководство по агрегации.
exists()
¶
-
exists
()¶
Возвращает True
, если QuerySet
содержит какие-либо результаты, и False
, если нет. Он пытается выполнить запрос самым простым и быстрым способом, но он выполняет почти тот же запрос, что и обычный QuerySet
.
exists()
полезен для поиска, относящегося как к членству объекта в QuerySet
, так и к существованию любых объектов в QuerySet
, особенно в контексте большой QuerySet
.
Наиболее эффективный метод определения, является ли модель с уникальным полем (например, primary_key
) членом QuerySet
, это:
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
print("Entry contained in queryset")
Который будет быстрее, чем следующий, который требует оценки и итерации по всему набору запросов:
if entry in some_queryset:
print("Entry contained in QuerySet")
И чтобы узнать, содержит ли набор запросов какие-либо элементы:
if some_queryset.exists():
print("There is at least one object in some_queryset")
Который будет быстрее, чем
if some_queryset:
print("There is at least one object in some_queryset")
… но не в значительной степени (следовательно, для повышения эффективности требуется большой набор запросов).
Кроме того, если some_queryset
еще не был проанализирован, но вы знаете, что это произойдет в какой-то момент, то использование some_queryset.exists()
сделает более общую работу (один запрос для проверки существования плюс дополнительный для последующего извлечения результатов), а не просто bool(some_queryset)
, который извлекает результаты и затем проверяет, были ли какие-либо возвращены.
update()
¶
-
update
(**kwargs)¶
Выполняет запрос на обновление SQL для указанных полей и возвращает количество совпадающих строк (которое может не совпадать с количеством обновленных строк, если некоторые строки уже имеют новое значение).
Например, чтобы отключить комментарии для всех записей блога, опубликованных в 2010 году, вы можете сделать это:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(Предполагается, что ваша модель Entry
имеет поля pub_date
и comments_on
.)
Вы можете обновить несколько полей - нет ограничений на их количество. Например, здесь мы обновляем поля comments_on
и headline
:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
Метод update()
применяется мгновенно, и единственное ограничение на обновляемый QuerySet
заключается в том, что он может обновлять только столбцы в основной таблице модели, но не в связанных моделях. Вы не можете сделать так, например:
>>> Entry.objects.update(blog__name='foo') # Won't work!
Фильтрация на основе связанных полей все еще возможна, хотя:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
Вы не можете вызвать update()
для QuerySet
, у которого был взят фрагмент или который больше не может быть отфильтрован.
Метод update()
возвращает количество затронутых строк:
>>> Entry.objects.filter(id=64).update(comments_on=True)
1
>>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
0
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132
Если вы просто обновляете запись и вам не нужно ничего делать с объектом модели, наиболее эффективным подходом является вызов update()
вместо загрузки объекта модели в память. Например, вместо этого:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
…сделайте это:
Entry.objects.filter(id=10).update(comments_on=False)
Использование update()
также предотвращает состояние гонки, при котором что-то может измениться в вашей базе данных за короткий промежуток времени между загрузкой объекта и вызовом save()
.
Наконец, следует понимать, что update()
выполняет обновление на уровне SQL и, таким образом, не вызывает никаких методов save()
в ваших моделях и не генерирует pre_save
или post_save
(которые являются следствием вызова Model.save()
). Если вы хотите обновить группу записей для модели, имеющей пользовательский метод save()
, выполните их в цикле и вызовите save()
, как тут:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
Сортировка набора¶
Связь order_by()
с update()
поддерживается только в MariaDB и MySQL и игнорируется для других баз данных. Это полезно для обновления уникального поля в указанном порядке без конфликтов. Например:
Entry.objects.order_by('-number').update(number=F('number') + 1)
Примечание
order_by()
clause will be ignored if it contains annotations, inherited
fields, or lookups spanning relations.
delete()
¶
-
delete
()¶
Выполняет запрос на удаление 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, {'weblog.Entry': 2, 'weblog.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, {'weblog.Blog': 1, 'weblog.Entry': 2, 'weblog.Entry_authors': 2})
Это каскадное поведение настраивается с помощью аргумента on_delete
для ForeignKey
.
Метод delete()
выполняет массовое удаление и не вызывает никаких методов delete()
в ваших моделях. Однако он генерирует сигналы pre_delete
и post_delete
для всех удаленных объектов (включая каскадные удаления).
Django должен извлекать объекты в память для отправки сигналов и обработки каскадов. Однако, если нет каскадов и нет сигналов, тогда Django может использовать ускоренный путь и удалять объекты без загрузки в память. Для больших удалений это может привести к значительному сокращению использования памяти. Количество выполненных запросов также может быть уменьшено.
Внешние ключи, для которых установлено on_delete
DO_NOTHING
, не мешают использовать быстрый путь при удалении.
Обратите внимание, что запросы, сгенерированные при удалении объекта, являются деталями реализации, которые могут быть изменены.
as_manager()
¶
-
classmethod
as_manager
()¶
Метод класса, который возвращает экземпляр Manager
с копией методов QuerySet
. Смотрите Создание менеджера с помощью методов QuerySet для более подробной информации.
explain()
¶
-
explain
(format=None, **options)¶
Возвращает строку плана выполнения 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
.
Добавлена поддержка формата 'TREE'
в MySQL 8.0.16+ и опция analysis
в MariaDB и MySQL 8.0.18+.
Поиск 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;
Не рекомендуется, начиная с версии 3.1: Использование не булевых значений в качестве правой части устарело, используйте взамен True
или False
. В Django 4.0 будет выбрасываться исключение.
regex
¶
Чувствительное к регистру совпадение регулярного выражения.
Синтаксис регулярного выражения - это используемый серверный компонент базы данных. В случае SQLite, который не имеет встроенной поддержки регулярных выражений, эта функция обеспечивается пользовательской функцией REGEXP (Python), поэтому синтаксис регулярного выражения является синтаксисом модуля re
в Python.
Пример:
Entry.objects.get(title__regex=r'^(An?|The) +')
SQL-эквивалент:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL
SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle
SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Рекомендуется использовать необработанные строки (например, r'foo'
вместо 'foo'
) для передачи синтаксиса регулярного выражения.
iregex
¶
Нечувствительное к регистру совпадение регулярного выражения.
Пример:
Entry.objects.get(title__iregex=r'^(an?|the) +')
SQL-эквивалент:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL
SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle
SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Агрегационные функции¶
Django предоставляет следующие функции агрегирования в модуле django.db.models
. Подробнее о том, как использовать эти агрегатные функции, смотрите руководство по агрегации тем. Обратитесь к документации Aggregate
, чтобы узнать, как создавать агрегаты.
Предупреждение
SQLite не может обрабатывать агрегирование полей даты/времени «из коробки». Это связано с тем, что в SQLite нет собственных полей даты и времени, а Django в настоящее время эмулирует эти функции с помощью текстового поля. Попытки использовать агрегирование полей даты/времени в SQLite вызовут NotSupportedError
.
Примечание
Функции агрегирования возвращают None
при использовании с пустым QuerySet
. Например, функция агрегирования Sum
возвращает None
вместо 0
, если QuerySet
не содержит записей. Исключением является Count
, который возвращает 0
, если QuerySet
пуст.
Все агрегаты имеют следующие общие параметры:
expressions
¶
Строки, которые ссылаются на поля в модели, преобразования поля или выражения запроса.
Добавлена поддержка преобразований поля.
output_field
¶
Необязательный аргумент, представляющий поле модели возвращаемого значения
Примечание
При объединении нескольких типов полей Django может определить output_field
, только если все поля одного типа. В противном случае вы должны предоставить output_field
самостоятельно.
filter
¶
Необязательный Q object
, который используется для фильтрации агрегируемых строк.
Смотрите Условная агрегация и Фильтрация по аннотациям.
**extra
¶
Аргументы ключевых слов, которые могут предоставить дополнительный контекст для SQL, сгенерированного агрегатом.
Avg
¶
-
class
Avg
(expression, output_field=None, distinct=False, filter=None, **extra)[исходный код]¶ Возвращает среднее значение заданного выражения, которое должно быть числовым, если вы не укажете другое
output_field
.- Псевдоним по умолчанию:
<field>__avg
- Тип возвращаемого значения:
float
, если на входеint
, в остальном то же самое, что и поле ввода, илиoutput_field
, если он указан
Имеет один необязательный аргумент:
-
distinct
¶ Если
Different=True
,Avg
возвращает среднее значение уникальных значений. Это SQL-эквивалентAVG(DISTINCT <field>)
. Значением по умолчанию являетсяFalse
.
- Псевдоним по умолчанию:
Count
¶
-
class
Count
(expression, distinct=False, filter=None, **extra)[исходный код]¶ Возвращает количество объектов, связанных через предоставленное выражение.
- Псевдоним по умолчанию:
<field>__count
- Тип возврата: `` int``
Имеет один необязательный аргумент:
-
distinct
¶ Если
distinct=True
, в число будут включены только уникальные экземпляры. Это эквивалент SQLCOUNT (DISTINCT <field>)
. Значением по умолчанию являетсяFalse
.
- Псевдоним по умолчанию:
Max
¶
-
class
Max
(expression, output_field=None, filter=None, **extra)[исходный код]¶ Возвращает максимальное значение данного выражения.
- Псевдоним по умолчанию:
<field>__max
- Тип возвращаемого значения: такой же, как у поля ввода, или
output_field
, если указано
- Псевдоним по умолчанию:
Min
¶
-
class
Min
(expression, output_field=None, filter=None, **extra)[исходный код]¶ Возвращает минимальное значение данного выражения.
- Псевдоним по умолчанию:
<field>__min
- Тип возвращаемого значения: такой же, как у поля ввода, или
output_field
, если указано
- Псевдоним по умолчанию:
StdDev
¶
-
class
StdDev
(expression, output_field=None, sample=False, filter=None, **extra)[исходный код]¶ Возвращает стандартное отклонение данных в предоставленном выражении.
- Псевдоним по умолчанию:
<field>__stddev
- Тип возвращаемого значения:
float
, если на входеint
, в остальном то же самое, что и поле ввода, илиoutput_field
, если он указан
Имеет один необязательный аргумент:
-
sample
¶ По умолчанию
StdDev
возвращает стандартное отклонение популяции. Однако, еслиsample=True
, возвращаемое значение будет стандартным отклонением выборки.
- Псевдоним по умолчанию:
Sum
¶
-
class
Sum
(expression, output_field=None, distinct=False, filter=None, **extra)[исходный код]¶ Вычисляет сумму всех значений данного выражения.
- Псевдоним по умолчанию:
<field>__sum
- Тип возвращаемого значения: такой же, как у поля ввода, или
output_field
, если указано
Имеет один необязательный аргумент:
-
distinct
¶ Если
distinct=True
,Sum
возвращает сумму уникальных значений. Это SQL-эквивалентSUM(DISTINCT <field>)
. Значением по умолчанию являетсяFalse
.
- Псевдоним по умолчанию:
Variance
¶
-
class
Variance
(expression, output_field=None, sample=False, filter=None, **extra)[исходный код]¶ Возвращает дисперсию данных в предоставленном выражении.
- Псевдоним по умолчанию:
<field>__variance
- Тип возвращаемого значения:
float
, если на входеint
, в остальном то же самое, что и поле ввода, илиoutput_field
, если он указан
Имеет один необязательный аргумент:
-
sample
¶ По умолчанию
Variance
возвращает дисперсию популяции. Однако, еслиsample=True
, возвращаемым значением будет выборочная дисперсия.
- Псевдоним по умолчанию: