Справочник по API QuerySet

Этот документ описывает детали API QuerySet. Он основан на материале, представленном в руководствах модель и запросы к базе данных, так что вы, вероятно, захотите прочитать и понять эти документы, прежде чем читать этот.

Во всем этом справочнике мы будем использовать example blog models, представленные в database query guide.

Когда выполняются QuerySet

Внутренне QuerySet может быть создан, отфильтрован, нарезан и, как правило, передан без фактического запроса к базе данных. На самом деле никаких действий с базой данных не происходит, пока вы не сделаете что-то для оценки набора запросов.

Вы можете выполнить QuerySet следующими способами:

  • Итерация. QuerySet является итеративным, и он выполняет свой запрос к базе данных при первой итерации по нему. Например, это напечатает заголовок всех записей в базе данных:

    for e in Entry.objects.all():
        print(e.headline)
    

    Примечание: не используйте это, если все, что вы хотите сделать, это определить, существует ли хотя бы один результат. Более эффективно использовать exists().

  • Асинхронная итерация.. По QuerySet можно также выполнять итерацию с помощью async for:

    async for e in Entry.objects.all():
      results.append(e)
    

    И синхронные, и асинхронные итераторы QuerySets используют один и тот же базовый кэш.

    Changed in Django 4.1:

    Добавлена поддержка асинхронной итерации.

  • Срезы. Как объяснено в Ограничение 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'}]>

Вы не можете использовать pickle между версиями

Соленья `` QuerySets`` действительны только для той версии Django, которая использовалась для их генерации. Если вы генерируете рассол с использованием Django версии N, нет никакой гарантии, что рассол будет читаем с Django версии N + 1. Соленые огурцы не должны использоваться как часть долгосрочной архивной стратегии.

Так как ошибки совместимости с помощью pickle могут быть трудно диагностируемыми, например, незаметно поврежденные объекты, возникает RuntimeWarning, когда вы пытаетесь открепить набор запросов в версии Django, отличной от той, в которой он был выбран.

QuerySet API

Вот формальное объявление QuerySet:

class QuerySet(model=None, query=None, using=None, hints=None)[исходный код]

Обычно работа с QuerySet состоит в использовании цепочек фильтров. Для этого большинство методов QuerySet возвращает новый «queryset». Эти методы подробно описаны ниже в этом разделе.

Класс QuerySet имеет следующие публичные атрибуты, которые можно использовать для интроспекции:

ordered

True, если QuerySet упорядочен - т.е. имеет order_by() или сортировку по умолчанию для модели, иначе False.

db

База данных, которая будет использоваться, если этот запрос выполняется сейчас.

Примечание

Параметр query для QuerySet существует для того, чтобы специализированные подклассы запросов могли реконструировать внутреннее состояние запроса. Значение параметра является непрозрачным представлением этого состояния запроса и не является частью общедоступного API.

Методы, которые возвращают новый QuerySet

Django предоставляет ряд методов уточнения QuerySet, которые изменяют либо типы результатов, возвращаемых QuerySet, либо способ выполнения его SQL-запроса.

Примечание

Эти методы не выполняют запросы к базе данных, поэтому они безопасны для запуска в асинхронном коде, и не имеют отдельных асинхронных версий.

filter()

filter(*args, **kwargs)

Возвращает новый QuerySet, содержащий объекты, которые соответствуют заданным параметрам поиска.

Параметры поиска (**kwargs) должны быть в формате, описанном в Полевые поиски ниже. Несколько параметров объединяются через `` И`` в базовом операторе SQL.

Если вам необходимо выполнить более сложные запросы (например, запросы с операторами OR), вы можете использовать Q objects (*args).

exclude()

exclude(*args, **kwargs)

Возвращает новый QuerySet, содержащий объекты, которые не соответствуют указанным параметрам поиска.

Параметры поиска (**kwargs) должны быть в формате, описанном в Поиск по полям ниже. Несколько параметров объединяются с помощью AND в базовом операторе SQL, и все это заключено в ``NOT() ``.

Этот пример исключает все записи, чье pub_date позже, чем 2005-1-3 И чьи headline равно «Hello»:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

В терминах SQL это оценивается как:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

В этом примере исключаются все записи, чье ``pub_date` позже, чем 2005-1-3 ИЛИ с заголовком «Hello»:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

В терминах SQL это оценивается как:

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

Обратите внимание, что второй пример является более ограничительным.

Если вам необходимо выполнить более сложные запросы (например, запросы с операторами OR), вы можете использовать Q objects (*args).

annotate()

annotate(*args, **kwargs)

Аннотирует каждый объект в QuerySet с помощью предоставленного списка выражений запроса. Выражение может быть простым значением, ссылкой на поле в модели (или любых связанных моделях) или агрегированным выражением (средние значения, суммы и т.д.), которое было вычислено для объектов, связанных с объектами в QuerySet.

Каждый аргумент annotate() является аннотацией, которая будет добавлена к каждому объекту в QuerySet, который возвращается.

Функции агрегации, предоставляемые Django, описаны в Функции агрегации ниже.

Аннотации, указанные с помощью ключевых аргументов, будут использовать ключевое слово в качестве псевдонима для аннотации. Для анонимных аргументов будет создан псевдоним, основанный на имени агрегатной функции и агрегируемого поля модели. Только агрегатные выражения, которые ссылаются на одно поле, могут быть анонимными аргументами. Все остальное должно быть ключевым аргументом.

Например, если вы манипулировали списком блогов, вы можете определить, сколько записей было сделано в каждом блоге:

>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

Модель Blog не определяет атрибут entry__count сама по себе, но с помощью ключевого аргумента для указания агрегатной функции вы можете контролировать имя аннотации:

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42

Подробное обсуждение агрегации смотрите в руководство по агрегации.

alias()

alias(*args, **kwargs)

То же, что annotate(), но вместо аннотирования объектов в QuerySet сохраняет выражение для последующего повторного использования с другими методами QuerySet. Это полезно, когда результат самого выражения не нужен, но он используется для фильтрации, упорядочивания или как часть сложного выражения. Если не выбрать неиспользуемое значение, из базы данных удаляется избыточная работа, что должно привести к повышению производительности.

Например, если вы хотите найти блоги с более чем 5 записями, но не интересуетесь точным количеством записей, вы можете сделать это:

>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count('entry')).filter(entries__gt=5)

alias() можно использовать вместе с annotate(), exclude(), filter(), order_by() и update(). Чтобы использовать выражение с псевдонимом с другими методами (например aggregate()), вы должны преобразовать его в аннотацию:

Blog.objects.alias(entries=Count('entry')).annotate(
    entries=F('entries'),
).aggregate(Sum('entries'))

filter() и order_by() могут принимать выражения напрямую, но построение и использование выражений часто не происходит в одном и том же месте (например, метод QuerySet создает выражения для последующего использования в представлениях). alias() позволяет создавать сложные выражения постепенно, возможно, охватывая несколько методов и модулей, ссылаться на части выражения по их псевдонимам и использовать только annotate() для окончательного результата.

order_by()

order_by(*fields)

По умолчанию результаты, возвращаемые QuerySet, упорядочиваются с помощью кортежа, заданного параметром ordering в классе Meta модели. Вы можете переопределить это для каждого QuerySet, используя метод order_by.

Пример:

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

Приведенный выше результат будет упорядочен по убыванию pub_date, затем по возрастанию headline. Отрицательный знак перед "-pub_date" указывает нисходящий порядок. Восходящий порядок подразумевается. Чтобы упорядочить случайным образом, используйте "?", например так:

Entry.objects.order_by('?')

Примечание: запросы order_by('?') могут быть дорогими и медленными, в зависимости от используемой вами базы данных.

Чтобы упорядочить по полю в другой модели, используйте тот же синтаксис, что и при запросах к отношениям модели. То есть имя поля, за которым следует двойное подчеркивание (__), за которым следует имя поля в новой модели и т.д. для всех моделей, к которым вы хотите присоединиться. Например:

Entry.objects.order_by('blog__name', 'headline')

Если вы попытаетесь упорядочить по полю, которое относится к другой модели, Django будет использовать упорядочение по умолчанию для связанной модели или упорядочить по первичному ключу связанной модели, если его нет :attr: Meta.ordering <django.db .models.Options.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, который имеет определенную сортировку (например, при запросе к модели, которая определяет сортировку по умолчанию, или при использовании: meth: 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'}, ...]>

Предупреждение

Потому что :class:` ~ django.db.models.ManyToManyField` атрибуты и обратные отношения могут иметь несколько связанных строк, в том числе они могут повлиять на размер набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в ваш запрос values(), и в этом случае будут возвращены все возможные комбинации.

Специальные значения для JSONField в SQLite

Из-за того, как функции SQL JSON_EXTRACT и JSON_TYPE реализованы в SQLite, и отсутствия типа данных BOOLEAN, values() будет возвращать True, False и None вместо "true", "false" и "null" строк для JSONField ключевых преобразований.

values_list()

values_list(*fields, flat=False, named=False)

Это похоже на values(), за исключением того, что вместо возврата словарей он возвращает кортежи при повторении. Каждый кортеж содержит значение из соответствующего поля или выражения, переданное в вызов values_list() - поэтому первый элемент является первым полем и т.д. Например:

>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>

Если вы передаете только одно поле, вы также можете передать параметр flat. Если True, это будет означать, что возвращаемые результаты будут единичными значениями, а не кортежем. Пример должен прояснить разницу:

>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>

>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>

Ошибочно передавать в flat, когда имеется более одного поля.

Вы можете передать `` named = True`` для получения результатов в виде: func: ~ python: collection.namedtuple

>>> Entry.objects.values_list('id', 'headline', named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>

Использование именованного кортежа может сделать результаты более читабельными за счет небольшого снижения производительности за преобразование результатов в именованный кортеж.

Если вы не передадите никаких значений в values_list(), он вернет все поля в модели в том порядке, в котором они были объявлены.

Общей необходимостью является получение определенного значения поля определенного экземпляра модели. Для этого используйте values_list(), а затем get():

>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'

values() и values_list() предназначены для оптимизации для конкретного случая использования: извлечение подмножества данных без затрат на создание экземпляра модели. Эта метафора разваливается при работе со многими ко многим и другими многозначными отношениями (такими как отношение «один ко многим» обратного внешнего ключа), потому что предположение «одна строка, один объект» не выполняется.

Например, обратите внимание на поведение при запросе через ManyToManyField:

>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
 ('George Orwell', 'Why Socialists Do Not Believe in Fun'),
 ('George Orwell', 'In Defence of English Cooking'),
 ('Don Quixote', None)]>

Авторы с несколькими записями появляются несколько раз, а авторы без записей имеют None для заголовка записи.

Аналогично, при запросе обратного внешнего ключа, None появляется для записей, не имеющих автора:

>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>

Специальные значения для JSONField в SQLite

Из-за того, как функции SQL JSON_EXTRACT и JSON_TYPE реализованы в SQLite, и отсутствия типа данных BOOLEAN, values_list() будет возвращать True, False и None вместо "true", "false" и "null" строк для JSONField ключевых преобразований.

dates()

dates(field, kind, order='ASC')

Возвращает QuerySet, который вычисляет список объектов datetime.date, представляющих все доступные даты определенного вида в QuerySet.

field должно быть именем DateField вашей модели. kind должен быть либо "year", "month", "week", либо "day". Каждый объект datetime.date в списке результатов «усекается» до заданного type.

  • "year" возвращает список всех различных значений года.
  • "month" возвращает список всех различных значений года/месяца.
  • "week" возвращает список всех различных значений года/недели. Все даты будут понедельником.
  • "day" возвращает список всех различных значений года/месяца/дня.

order, который по умолчанию равен 'ASC', должен быть либо 'ASC', либо 'DESC'. Это указывает, как сортировать результаты.

Примеры:

>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'week')
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]

datetimes()

datetimes(field_name, kind, order='ASC', tzinfo=None, is_dst=None)

Возвращает QuerySet, который оценивает список объектов datetime.datetime, представляющих все доступные даты определенного вида в содержимом QuerySet.

field_name` должно быть именем ``DateTimeField вашей модели.

kind должен быть одним из: "year", "month", "week", "day", "hour", "minute", "second". Каждый объект datetime.datetime в списке результатов «усекается» до заданного type.

order, который по умолчанию равен 'ASC', должен быть либо 'ASC', либо 'DESC'. Это указывает, как сортировать результаты.

tzinfo определяет часовой пояс, в который конвертируются даты и время перед усечением. Действительно, данная дата и время имеют разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo. Если это None, Django использует текущий часовой пояс. Это не действует, если USE_TZ равно False.

is_dst указывает, должен ли pytz интерпретировать несуществующие и неоднозначные даты в летнее время. По умолчанию (когда is_dst=None), pytz выдает исключение для таких datetime.

Не рекомендуется, начиная с версии 4.0: Параметр is_dst является устаревшим и будет удален в Django 5.0.

Примечание

Эта функция выполняет преобразование часового пояса непосредственно в базе данных. Как следствие, ваша база данных должна иметь возможность интерпретировать значение tzinfo.tzname(None). Это приводит к следующим требованиям:

  • SQLite: нет требований. Преобразования выполняются на языке Python.
  • PostgreSQL: никаких требований (см. Часовые пояса <time).
  • 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!

Вы можете прочитать больше о том, как работает SQL injection protection в Django.

По определению, эти дополнительные поиски могут не переноситься на разные механизмы баз данных (потому что вы явно пишете код 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. Вы можете вручную добавить таблицы в предложение SQL FROM, используя tables.

    where и tables принимают список строк. Все where параметры имеют значение «AND» для любых других критериев поиска.

    Пример:

    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    

    …переводит (примерно) в следующий SQL:

    SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
    

    Будьте осторожны при использовании параметра tables, если вы указываете таблицы, которые уже используются в запросе. Когда вы добавляете дополнительные таблицы с помощью параметра tables, Django предполагает, что вы хотите, чтобы таблица включала дополнительное время, если оно уже включено. Это создает проблему, так как имя таблицы будет иметь псевдоним. Если таблица появляется в операторе SQL несколько раз, второе и последующие вхождения должны использовать псевдонимы, чтобы база данных могла различать их. Если вы ссылаетесь на дополнительную таблицу, которую вы добавили в дополнительный параметр where, это приведет к ошибкам.

    Обычно вы будете добавлять только дополнительные таблицы, которые еще не отображаются в запросе. Однако, если описанный выше случай действительно имеет место, есть несколько решений. Во-первых, посмотрите, сможете ли вы обойтись без включения дополнительной таблицы и используйте ту, которая уже есть в запросе. Если это невозможно, поместите ваш вызов extra() в начале конструкции набора запросов, чтобы ваша таблица использовалась первой в этой таблице. Наконец, если ничего не помогает, посмотрите на полученный запрос и перепишите свое дополнение where, чтобы использовать псевдоним, указанный в вашей дополнительной таблице. Псевдоним будет одинаковым каждый раз, когда вы создаете набор запросов одинаковым образом, поэтому вы можете положиться на имя псевдонима, которое не изменится.

  • order_by

    Если вам нужно упорядочить результирующий набор запросов, используя некоторые из новых полей или таблиц, которые вы включили через extra(), используйте параметр order_by для extra() и передайте последовательность строк. Эти строки должны быть либо полями модели (как в обычном методе order_by() для наборов запросов), формы table_name.column_name или псевдонимом для столбца, который вы указали в select параметре для extra().

    Например:

    q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    q = q.extra(order_by = ['-is_recent'])
    

    Это отсортировало бы все элементы, для которых is_recent является верным в начало набора результатов (True сортирует перед False в порядке убывания).

    Между прочим, это показывает, что вы можете сделать несколько вызовов extra(), и он будет вести себя так, как вы ожидаете (добавляя новые ограничения каждый раз).

  • params

    Описанный выше параметр where может использовать стандартные строковые заполнители базы данных Python - '%s' для указания параметров, которые механизм базы данных должен автоматически заключать в кавычки. Аргумент params - это список любых дополнительных параметров, которые нужно заменить.

    Пример:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

    Всегда используйте params вместо встраивания значений непосредственно в where, потому что params обеспечит правильное экранирование значений в соответствии с вашим конкретным бэкэндом. Например, кавычки будут экранированы правильно.

    Плохо:

    Entry.objects.extra(where=["headline='Lennon'"])
    

    Хорошо:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

Предупреждение

Если вы выполняете запросы к MySQL, обратите внимание, что принудительное приведение типов в MySQL может привести к неожиданным результатам при смешивании типов. Если вы запрашиваете столбец строкового типа, но с целочисленным значением, MySQL перед выполнением сравнения преобразует типы всех значений в таблице в целое число. Например, если ваша таблица содержит значения 'abc', 'def' и вы запрашиваете WHERE mycolumn=0, обе строки будут совпадать. Чтобы предотвратить это, выполните правильное приведение типов перед использованием значения в запросе.

defer()

defer(*fields)

В некоторых сложных ситуациях моделирования данных ваши модели могут содержать много полей, некоторые из которых могут содержать много данных (например, текстовые поля), или требовать дорогостоящей обработки для преобразования их в объекты Python. Если вы используете результаты набора запросов в какой-то ситуации, когда вы не знаете, нужны ли вам эти конкретные поля при первоначальном извлечении данных, вы можете указать Django не извлекать их из базы данных.

Это делается путем передачи имен полей, которые не загружаются, в defer():

Entry.objects.defer("headline", "body")

Набор запросов с отложенными полями будет по-прежнему возвращать экземпляры модели. Каждое отложенное поле будет извлечено из базы данных, если вы получите доступ к этому полю (по одному, а не ко всем отложенным полям одновременно).

Примечание

Отложенные поля не будут лениво загружаться таким образом из асинхронного кода. Вместо этого вы получите исключение SynchronousOnlyOperation. Если вы пишете асинхронный код, вам не следует пытаться получить доступ к полям, которые вы defer().

Вы можете сделать несколько вызовов defer(). Каждый вызов добавляет новые поля в отложенный набор:

# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")

Порядок, в котором поля добавляются в отложенный набор, не имеет значения. Вызов defer() с именем поля, которое уже было отложено, безвреден (поле все равно будет отложено).

Вы можете отложить загрузку полей в связанных моделях (если связанные модели загружаются через select_related()), используя стандартную запись двойного подчеркивания для разделения связанных полей:

Blog.objects.select_related().defer("entry__headline", "entry__body")

Если вы хотите очистить набор отложенных полей, передайте None в качестве параметра в defer():

# Load all fields immediately.
my_queryset.defer(None)

Некоторые поля в модели не будут отложены, даже если вы укажете их. Вы никогда не сможете отложить загрузку первичного ключа. Если вы используете select_related() для извлечения связанных моделей, вы не должны откладывать загрузку поля, соединяющего основную модель с связанной, это приведет к ошибке.

Примечание

Метод defer() (и его двоюродный брат only(), ниже) предназначены только для расширенных вариантов использования. Они обеспечивают оптимизацию, когда вы тщательно проанализировали свои запросы и точно поняли, какая информация вам нужна, и измерили, что разница между возвратом необходимых вам полей и полным набором полей для модели будет значительной.

Even if you think you are in the advanced use-case situation, only use defer() when you cannot, at queryset load time, determine if you will need the extra fields or not. If you are frequently loading and using a particular subset of your data, the best choice you can make is to normalize your models and put the non-loaded data into a separate model (and database table). If the columns must stay in the one table for some reason, create a model with Meta.managed = False (see the managed attribute documentation) containing just the fields you normally need to load and use that where you might otherwise call defer(). This makes your code more explicit to the reader, is slightly faster and consumes a little less memory in the Python process.

Например, обе эти модели используют одну и ту же базовую таблицу базы данных:

class CommonlyUsedModel(models.Model):
    f1 = models.CharField(max_length=10)

    class Meta:
        managed = False
        db_table = 'app_largetable'

class ManagedModel(models.Model):
    f1 = models.CharField(max_length=10)
    f2 = models.CharField(max_length=10)

    class Meta:
        db_table = 'app_largetable'

# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer('f2')

Если в неуправляемой модели необходимо дублировать многие поля, может быть лучше создать абстрактную модель с общими полями, а затем иметь неуправляемые и управляемые модели, наследуемые от абстрактной модели.

Примечание

При вызове save() для экземпляров с отложенными полями будут сохранены только загруженные поля. Смотрите save() для более подробной информации.

only()

only(*fields)

Метод only() по сути противоположен методу defer(). Только поля, переданные в этот метод и не уже указанные как отложенные, загружаются немедленно при оценке набора запросов.

If you have a model where almost all the fields need to be deferred, using only() to specify the complementary set of fields can result in simpler code.

Предположим, у вас есть модель с полями name, age и biography. Следующие два набора запросов одинаковы с точки зрения отложенных полей:

Person.objects.defer("age", "biography")
Person.objects.only("name")

Всякий раз, когда вы вызываете only(), он заменяет набор полей для немедленной загрузки. Имя метода мнемоническое: только эти поля загружаются немедленно. Остальные откладываются. Таким образом, последовательные вызовы only() приводят только к рассмотрению последних полей:

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

Поскольку defer() действует постепенно (добавляя поля в отложенный список), вы можете комбинировать вызовы only() и defer(), и все будет вести себя логически:

# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")

# Final result loads headline immediately.
Entry.objects.defer("body").only("headline", "body")

Все предостережения в примечании к документации defer() относятся и к only(). Используйте его осторожно и только после того, как исчерпаете ваши другие возможности.

Использование only() и пропуск поля, запрошенного с использованием select_related(), также является ошибкой.

Как и в случае с defer(), вы не можете получить доступ к незагруженным полям из асинхронного кода и ожидать, что они загрузятся. Вместо этого вы получите исключение SynchronousOnlyOperation. Убедитесь, что все поля, к которым вы можете получить доступ, находятся в вашем вызове only().

Примечание

При вызове save() для экземпляров с отложенными полями будут сохранены только загруженные поля. Смотрите save() для более подробной информации.

Примечание

При использовании defer() после only() поля в defer() будут иметь приоритет над only() для полей, перечисленных в обоих.

using()

using(alias)

Этот метод предназначен для указания какую базу данных QuerySet будет использовать, если вы используете более одной базы данных. Единственный аргумент, который принимает этот метод - это псевдоним базы данных, как определено в DATABASES.

Например:

# queries the database with the 'default' alias.
>>> Entry.objects.all()

# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')

select_for_update()

select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)

Возвращает набор запросов, который блокирует строки до конца транзакции, генерируя оператор SQL SELECT ... FOR UPDATE для поддерживаемых баз данных.

Например:

from django.db import transaction

entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
    for entry in entries:
        ...

Когда набор запросов выполняется (в данном случае for entry in entries), все совпадающие записи будут заблокированы до конца блока транзакции, что означает, что другие транзакции не смогут изменить или получить блокировки для них.

Обычно, если другая транзакция уже получила блокировку в одной из выбранных строк, запрос будет блокироваться до тех пор, пока блокировка не будет снята. Если это не то поведение, которое вам нужно, вызовите select_for_update(nowait=True). Это сделает вызов неблокирующим. Если конфликтующая блокировка уже получена другой транзакцией, то при оценке набора запросов будет вызвано DatabaseError. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True). nowait и skip_locked являются взаимоисключающими и попытки вызвать select_for_update() с включенными обеими опциями приведут к ValueError.

По умолчанию select_for_update() блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанных в select_related(), блокируются в дополнение к строкам модели набора запросов. Если это нежелательно, укажите связанные объекты, которые вы хотите заблокировать, в select_for_update(of=(...)), используя тот же синтаксис полей, что и select_related(). Используйте значение 'self' для ссылки на модель набора запросов.

Блокировка родительских моделей в select_for_update(of=(...))

Если вы хотите заблокировать родительские модели при использовании наследование нескольких таблиц, вы должны указать поля родительской ссылки (по умолчанию <parent_model_name>_ptr) в аргументе of. Например:

Restaurant.objects.select_for_update(of=('self', 'place_ptr'))

Использование select_for_update(of=(...)) с указанными полями

Если вы хотите заблокировать модели и указать выбранные поля, например, используя values(), вы должны выбрать хотя бы одно поле из каждой модели в аргументе of. Модели без выбранных полей не будут заблокированы.

Только в PostgreSQL вы можете передать no_key=True, чтобы получить более слабую блокировку, которая по-прежнему позволяет создавать строки, которые просто ссылаются на заблокированные строки (например, через внешний ключ), пока блокировка установлена. В документации PostgreSQL есть более подробная информация о режимах блокировки на уровне строк.

Вы не можете использовать 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 поддерживает только аргумент nowait, MariaDB 10.6+ также поддерживает аргумент skip_locked, а 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.

Changed in Django 4.0:

Аргумент skip_locked был разрешен в MariaDB 10.6+.

raw()

raw(raw_query, params=(), translations=None, using=None)

Принимает необработанный SQL-запрос, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet. Этот экземпляр RawQuerySet может быть повторен, как обычный QuerySet, для предоставления экземпляров объекта.

Смотрите Выполнение необработанных SQL-запросов для получения дополнительной информации.

Предупреждение

raw() всегда запускает новый запрос и не учитывает предыдущую фильтрацию. Как таковой, он обычно должен вызываться из Manager или из свежего QuerySet.

Операторы, которые возвращают новый QuerySet

Комбинированные наборы запросов должны использовать одну и ту же модель.

AND (&)

Объединяет два QuerySet’а, используя оператор SQL AND.

Следующее эквивалентно:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))

SQL-эквивалент:

SELECT ... WHERE x=1 AND y=2

ИЛИ (|)

Объединяет два QuerySet’а, используя оператор SQL OR.

Следующее эквивалентно:

Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))

SQL-эквивалент:

SELECT ... WHERE x=1 OR y=2

| не является коммутативной операцией, так как могут быть сгенерированы различные (хотя и эквивалентные) запросы.

XOR (^)

New in Django 4.1.

Объединяет два QuerySetс помощью оператора SQL XOR.

Следующее эквивалентно:

Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) ^ Q(y=2))

SQL-эквивалент:

SELECT ... WHERE x=1 XOR y=2

Примечание

XOR поддерживается в MariaDB и MySQL. В других базах данных x ^ y ^ ... ^ z преобразуется в эквивалент:

(x OR y OR ... OR z) AND
1=(
    (CASE WHEN x THEN 1 ELSE 0 END) +
    (CASE WHEN y THEN 1 ELSE 0 END) +
    ...
    (CASE WHEN z THEN 1 ELSE 0 END) +
)

Методы, которые не возвращают QuerySet

Следующие методы QuerySet оценивают QuerySet и возвращают что-то отличное от QuerySet.

Эти методы не используют кеш (см .: ref: caching-and-querysets). Скорее, они запрашивают базу данных каждый раз, когда их вызывают.

Поскольку эти методы оценивают QuerySet, они являются блокирующими вызовами, и поэтому их основные (синхронные) версии не могут быть вызваны из асинхронного кода. По этой причине каждый из них имеет соответствующую асинхронную версию с префиксом a - например, вместо get(…) вы можете await aget(…).

Обычно нет никакой разницы в поведении, кроме их асинхронной природы, но любые различия отмечены ниже рядом с каждым методом.

Changed in Django 4.1:

Были добавлены асинхронные версии каждого метода с префиксом a.

get()

get(*args, **kwargs)
aget(*args, **kwargs)

Асинхронная версия: aget()

Возвращает объект, соответствующий заданным параметрам поиска, который должен быть в формате, описанном в Поиск полей. Вы должны использовать поиски, которые гарантированно уникальны, такие как первичный ключ или поля в ограничении уникальности. Например:

Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))

Если вы ожидаете, что набор запросов уже вернет одну строку, вы можете использовать get() без каких-либо аргументов, чтобы вернуть объект для этой строки:

Entry.objects.filter(pk=1).get()

Если get() не находит никаких объектов, возникает исключение Model.DoesNotExist:

Entry.objects.get(id=-999) # raises Entry.DoesNotExist

Если get() находит более одного объекта, он вызывает исключение Model.MultipleObjectsReturned:

Entry.objects.get(name='A Duplicated Name') # raises Entry.MultipleObjectsReturned

Оба эти класса исключений являются атрибутами класса модели и специфичны для этой модели. Если вы хотите обрабатывать такие исключения из нескольких вызовов get() для разных моделей, вы можете использовать их общие базовые классы. Например, вы можете использовать django.core.exceptions.ObjectDoesNotExist для обработки исключений DoesNotExist из нескольких моделей:

from django.core.exceptions import ObjectDoesNotExist

try:
    blog = Blog.objects.get(id=1)
    entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
    print("Either the blog or entry doesn't exist.")
Changed in Django 4.1:

Был добавлен метод aget().

create()

create(**kwargs)
acreate(*args, **kwargs)

Асинхронная версия: acreate()

Удобный метод для создания объекта и сохранения всего за один шаг. Таким образом:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

и:

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)

эквивалентны.

Параметр force_insert задокументирован в другом месте, но все это означает, что новый объект всегда будет создаваться. Обычно вам не нужно беспокоиться об этом. Однако, если ваша модель содержит заданное вами значение первичного ключа вручную, и если это значение уже существует в базе данных, вызов create() завершится неудачно с IntegrityError, так как первичные ключи должны быть уникальными. Будьте готовы обработать исключение, если вы используете первичные ключи вручную.

Changed in Django 4.1:

Был добавлен метод acreate().

get_or_create()

get_or_create(defaults=None, **kwargs)
aget_or_create(defaults=None, **kwargs)

Асинхронная версия: aget_or_create()

Удобный метод для поиска объекта с указанным kwargs (может быть пустым, если в вашей модели есть значения по умолчанию для всех полей), создавая его при необходимости.

Возвращает кортеж (object, created), где object - извлеченный или созданный объект, а created - логическое значение, указывающее, был ли создан новый объект.

Это предназначено для предотвращения создания дублирующихся объектов, когда запросы выполняются параллельно, и в качестве сокращения для упрощенного кода. Например:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

Здесь, при одновременных запросах, могут быть сделаны многочисленные попытки сохранить Person с одинаковыми параметрами. Чтобы избежать этого состояния гонки, приведенный выше пример можно переписать с помощью get_or_create(), например так:

obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

Любые ключевые аргументы, передаваемые в get_or_create() - за исключением необязательного аргумента, называемого defaults - будут использоваться в вызове get(). Если объект найден, get_or_create() возвращает кортеж этого объекта и False.

Предупреждение

Этот метод является атомарным, предполагая, что база данных обеспечивает уникальность ключевых аргументов (смотрите unique или unique_together). Если поля, используемые в аргументах ключевого слова, не имеют ограничения уникальности, одновременные вызовы этого метода могут привести к вставке нескольких строк с одинаковыми параметрами.

Вы можете указать более сложные условия для извлеченного объекта, связав get_or_create() с filter() и используя Q objects. Например, чтобы получить Роберта или Боба Марли, если таковой существует, и создать последний в противном случае:

from django.db.models import Q

obj, created = Person.objects.filter(
    Q(first_name='Bob') | Q(first_name='Robert'),
).get_or_create(last_name='Marley', defaults={'first_name': 'Bob'})

Если найдено несколько объектов, get_or_create() вызовет MultipleObjectsReturned. Если объект не найден, get_or_create() создаст и сохранит новый объект, возвращая кортеж из нового объекта и True. Новый объект будет создан примерно согласно этому алгоритму:

params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()

По-английски это означает, что начинать нужно с любого не ключевого аргумента 'defaults', который не содержит двойного подчеркивания (что указывает на неточный поиск). Затем добавьте содержимое defaults, переопределив любые ключи, если необходимо, и используйте результат в качестве аргументов ключевого слова для класса модели. Если в defaults есть какие-либо вызываемые элементы, выполните их. Как уже упоминалось выше, это упрощение алгоритма, который используется, но он содержит все соответствующие детали. Внутренняя реализация имеет больше проверок ошибок, чем эта, и обрабатывает некоторые дополнительные граничные условия; если вам интересно, прочитайте код.

Если у вас есть поле с именем defaults и вы хотите использовать его для точного поиска в get_or_create(), просто используйте 'defaults__exact', например, так:

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

Метод get_or_create() имеет схожее поведение ошибки с create(), когда вы используете указанные вручную первичные ключи. Если объект должен быть создан, а ключ уже существует в базе данных, будет вызвано IntegrityError.

Наконец, слово об использовании get_or_create() в представлениях Django. Обязательно используйте его только в запросах POST, если у вас нет веских причин не делать этого. Запросы GET не должны влиять на данные. Вместо этого используйте POST всякий раз, когда запрос страницы оказывает побочный эффект на ваши данные. Для получения дополнительной информации смотрите Безопасные методы в спецификации HTTP.

Предупреждение

Вы можете использовать get_or_create() через ManyToManyField атрибуты и обратные отношения. В этом случае вы будете ограничивать запросы в контексте этого отношения. Это может привести к некоторым проблемам с целостностью, если вы не используете его постоянно.

Имея следующие модели:

class Chapter(models.Model):
    title = models.CharField(max_length=255, unique=True)

class Book(models.Model):
    title = models.CharField(max_length=256)
    chapters = models.ManyToManyField(Chapter)

Вы можете использовать get_or_create() через поле глав книги, но оно извлекается только внутри контекста этой книги:

>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError

Это происходит потому, что он пытается получить или создать «Главу 1» через книгу «Улисс», но не может сделать ни одну из них: отношение не может извлечь эту главу, потому что оно не связано с этой книгой, но он также не может создать его, потому что поле title должно быть уникальным.

Changed in Django 4.1:

Был добавлен метод aget_or_create().

update_or_create()

update_or_create(defaults=None, **kwargs)
aupdate_or_create(defaults=None, **kwargs)

Асинхронная версия: aupdate_or_create()

Удобный метод для обновления объекта с указанным kwargs, создания нового при необходимости. defaults - это словарь пар (поле, значение), используемых для обновления объекта. Значения в defaults могут быть вызываемыми.

Возвращает кортеж (object, created), где object является созданным или обновленным объектом, а created является логическим значением, указывающим, был ли создан новый объект.

Метод update_or_create пытается извлечь объект из базы данных на основе заданного kwargs. Если совпадение найдено, оно обновляет поля, переданные в словаре defaults.

Это просто сокращение для упрощенного кода. Например:

defaults = {'first_name': 'Bob'}
try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in defaults.items():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    new_values = {'first_name': 'John', 'last_name': 'Lennon'}
    new_values.update(defaults)
    obj = Person(**new_values)
    obj.save()

Эта модель становится довольно громоздкой, так как количество полей в модели увеличивается. Приведенный выше пример можно переписать с помощью update_or_create(), например так:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

Подробное описание того, как разрешаются имена, переданные в kwargs, смотрите в get_or_create().

Как описано выше в get_or_create(), этот метод подвержен гоночному состоянию, которое может привести к одновременной вставке нескольких строк, если уникальность не обеспечивается на уровне базы данных.

Также как get_or_create() и create(), если вы используете указанные вручную первичные ключи, и объект должен быть создан, но ключ уже существует в базе данных, то это вызовет IntegrityError.

Changed in Django 4.1:

Был добавлен метод aupdate_or_create().

bulk_create()

bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
abulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)

Асинхронная версия: abulk_create()

Этот метод вставляет предоставленный список объектов в базу данных эффективным образом (обычно только 1 запрос, независимо от количества объектов), и возвращает созданные объекты в виде списка, в том же порядке, в котором они были предоставлены:

>>> objs = Entry.objects.bulk_create([
...     Entry(headline='This is a test'),
...     Entry(headline='This is only a test'),
... ])

Это имеет ряд предостережений, хотя:

  • Метод save() модели вызываться не будет, а сигналы pre_save и post_save не будут отправлены.

  • Он не работает с дочерними моделями в сценарии наследования нескольких таблиц.

  • Если первичный ключ модели является AutoField, атрибут первичного ключа может быть получен только в определенных базах данных (в настоящее время PostgreSQL, MariaDB 10.5+ и SQLite 3.35+). В других базах данных он не будет установлен.

  • Это не работает с отношениями «многие ко многим».

  • Он бросает objs в список, который полностью выполняет objs, если это генератор. Приведение позволяет проверять все объекты, так что любые объекты с вручную установленным первичным ключом могут быть вставлены первыми. Если вы хотите вставить объекты в пакет без одновременной оценки всего генератора, вы можете использовать эту технику, если у объектов нет установленных первичных ключей вручную:

    from itertools import islice
    
    batch_size = 100
    objs = (Entry(headline='Test %s' % i) for i in range(1000))
    while True:
        batch = list(islice(objs, batch_size))
        if not batch:
            break
        Entry.objects.bulk_create(batch, batch_size)
    

Параметр batch_size контролирует, сколько объектов создается в одном запросе. По умолчанию все объекты создаются в одном пакете, за исключением SQLite, где по умолчанию используется не более 999 переменных на запрос.

В базах данных, которые поддерживают это (все, кроме Oracle), установка параметра ignore_conflicts в значение True говорит базе данных игнорировать отказ вставки любых строк, которые не соответствуют ограничениям, таким как дублирование уникальных значений.

В базах данных, которые поддерживают это (все, кроме Oracle и SQLite < 3.24), установка параметра update_conflicts в значение True указывает базе данных обновить update_fields, когда вставка строки не удалась из-за конфликтов. В PostgreSQL и SQLite, в дополнение к update_fields, необходимо предоставить список unique_fields, которые могут быть в конфликте.

Включение параметра ignore_conflicts или update_conflicts отключает установку первичного ключа на каждом экземпляре модели (если база данных обычно поддерживает это).

Предупреждение

В MySQL и MariaDB установка параметра ignore_conflicts на True превращает определенные типы ошибок, кроме повторяющегося ключа, в предупреждения. Даже в строгом режиме. Например: недопустимые значения или нарушения, не допускающие значения NULL. Дополнительную информацию смотрите в документации MySQL и` документации MariaDB`_.

Changed in Django 4.0:

Добавлена поддержка получения атрибутов первичного ключа на SQLite 3.35+.

Changed in Django 4.1:

Параметры update_conflicts, update_fields и unique_fields были добавлены для поддержки обновления полей, когда вставка строки не удается из-за конфликта.

Был добавлен метод abulk_create().

bulk_update()

bulk_update(objs, fields, batch_size=None)
abulk_update(objs, fields, batch_size=None)

Асинхронная версия: abulk_update()

Этот метод эффективно обновляет заданные поля на предоставленных экземплярах модели, как правило, с помощью одного запроса, и возвращает количество обновленных объектов:

>>> objs = [
...    Entry.objects.create(headline='Entry 1'),
...    Entry.objects.create(headline='Entry 2'),
... ]
>>> objs[0].headline = 'This is entry 1'
>>> objs[1].headline = 'This is entry 2'
>>> Entry.objects.bulk_update(objs, ['headline'])
2
Changed in Django 4.0:

Возвращаемое значение количества обновленных объектов было добавлено.

QuerySet.update() используется для сохранения изменений, поэтому это более эффективно, чем перебирать список моделей и вызывать save() для каждой из них, но имеет несколько предостережений:

  • Вы не можете обновить первичный ключ модели.
  • Метод save() каждой модели не вызывается, и сигналы pre_save и post_save не отправлено.
  • При обновлении большого количества столбцов в большом количестве строк сгенерированный SQL может быть очень большим. Избегайте этого, указав подходящий batch_size.
  • Обновление полей, определенных в предках наследования нескольких таблиц, повлечет за собой дополнительный запрос для предка.
  • Если отдельный пакет содержит дубликаты, только первый экземпляр в этом пакете приведет к обновлению.
  • Количество обновленных объектов, возвращаемых функцией, может быть меньше, чем количество переданных объектов. Это может быть вызвано дублированием переданных объектов, которые обновляются в одной и той же партии, или условиями гонки, когда объекты больше не присутствуют в базе данных.

Параметр batch_size определяет, сколько объектов сохраняется в одном запросе. По умолчанию обновляются все объекты в одном пакете, кроме SQLite и Oracle, которые имеют ограничения по количеству переменных, используемых в запросе.

Changed in Django 4.1:

Был добавлен метод abulk_update().

count()

count()
acount()

Асинхронная версия: acount()

Возвращает целое число, представляющее количество объектов в базе данных, соответствующих QuerySet.

Пример:

# Returns the total number of entries in the database.
Entry.objects.count()

# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()

Вызов count() выполняет SELECT COUNT (*) за кулисами, поэтому вы всегда должны использовать count() вместо того, чтобы загружать всю запись в объекты Python и вызывать len() на результат (если вам все равно не нужно загружать объекты в память, в этом случае len() будет быстрее).

Обратите внимание, что если вы хотите подсчитать количество элементов в QuerySet и также извлекаете из него экземпляры модели (например, путем итерации по нему), возможно, более эффективно использовать len(queryset), который не вызывает дополнительный запрос к базе данных, как count().

Если набор запросов уже был полностью получен, count() будет использовать эту длину, а не выполнять дополнительный запрос к базе данных.

Changed in Django 4.1:

Был добавлен метод acount().

in_bulk()

in_bulk(id_list=None, *, field_name='pk')
ain_bulk(id_list=None, *, field_name='pk')

Асинхронная версия: ain_bulk()

Принимает список значений полей (id_list) и field_name для этих значений, и возвращает словарь, отображающий каждое значение на экземпляр объекта с заданным значением поля. Никакие исключения django.core.exceptions.ObjectDoesNotExist никогда не будут вызваны in_bulk; то есть, любое значение id_list, не соответствующее какому-либо экземпляру, будет просто проигнорировано. Если id_list не указан, возвращаются все объекты в наборе запросов. field_name должно быть уникальным полем или отличным полем (если в distinct() указано только одно поле). По умолчанию field_name - первичный ключ.

Пример:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct('name').in_bulk(field_name='name')
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}

Если вы передадите in_bulk() пустой список, вы получите пустой словарь.

Changed in Django 4.1:

Был добавлен метод ain_bulk().

iterator()

iterator(chunk_size=None)
aiterator(chunk_size=None)

Асинхронная версия: aiterator()

Оценивает QuerySet (выполняя запрос) и возвращает итератор (см. PEP 234) по результатам, или асинхронный итератор (см. PEP 492), если вы вызываете его асинхронную версию aiterator.

Итератор QuerySet обычно кэширует свои результаты внутри, чтобы повторные оценки не приводили к дополнительным запросам. Напротив, iterator() будет считывать результаты напрямую, без кэширования на уровне QuerySet (внутри итератор по умолчанию вызывает iterator() и кэширует возвращаемое значение). Для QuerySet, возвращающего большое количество объектов, к которым нужно обращаться только один раз, это может привести к повышению производительности и значительному сокращению памяти.

Обратите внимание, что использование iterator() на QuerySet, который уже был оценен, заставит его вычислять снова, повторяя запрос.

iterator() совместим с предыдущими вызовами prefetch_related() при условии, что задано chunk_size. Большие значения потребуют меньшего количества запросов для выполнения предварительной выборки за счет большего использования памяти.

Примечание

aiterator() не совместим с предыдущими вызовами prefetch_related().

В некоторых базах данных (например, Oracle, SQLite) максимальное количество терминов в предложении SQL IN может быть ограничено. Поэтому следует использовать значения ниже этого предела. (В частности, при предварительной выборке по двум или более отношениям, chunk_size должно быть достаточно маленьким, чтобы ожидаемое количество результатов для каждого предварительно выбранного отношения все еще было ниже предела).

До тех пор, пока QuerySet не выполняет предварительную выборку связанных объектов, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявное значение по умолчанию 2000.

В зависимости от серверной части базы данных результаты запроса будут загружаться одновременно или передаваться из базы данных с использованием серверных курсоров.

Changed in Django 4.1:

В iterator() была добавлена поддержка предварительной выборки связанных объектов.

Был добавлен метод aiterator().

Не рекомендуется, начиная с версии 4.1: Использование iterator() в наборе запросов, который осуществляет предварительную выборку связанных объектов без предоставления chunk_size, является устаревшим. В Django 5.0 будет возникать исключение.

С серверными курсорами

Oracle и PostgreSQL используют серверные курсоры для потоковой передачи результатов из базы данных без загрузки всего набора результатов в память.

Драйвер базы данных Oracle всегда использует серверные курсоры.

В случае серверных курсоров параметр chunk_size указывает количество результатов, которые необходимо кэшировать на уровне драйвера базы данных. Выборка больших кусков уменьшает количество циклов между драйвером базы данных и базой данных за счет памяти.

В PostgreSQL серверные курсоры будут использоваться, только если для параметра DISABLE_SERVER_SIDE_CURSORS установлено значение False. Прочитайте Объединение транзакций и курсоры на стороне сервера, если вы используете пул соединений, настроенный в режиме пула транзакций. Когда серверные курсоры отключены, поведение аналогично базам данных, которые не поддерживают серверные курсоры.

Без серверных курсоров

MySQL не поддерживает потоковые результаты, поэтому драйвер базы данных Python загружает весь набор результатов в память. Затем результирующий набор преобразуется в объекты строк Python с помощью адаптера базы данных с помощью метода fetchmany(), определенного в PEP 249.

SQLite может получать результаты в пакетах, используя fetchmany(), но поскольку SQLite не обеспечивает изоляцию между запросами в соединении, будьте осторожны при записи в таблицу, для которой выполняется итерация. Смотрите Изоляция при использовании QuerySet.iterator() для получения дополнительной информации.

Параметр chunk_size управляет размером пакетов, которые Django извлекает из драйвера базы данных. Большие пакеты уменьшают накладные расходы на связь с драйвером базы данных за счет небольшого увеличения потребления памяти.

До тех пор, пока QuerySet не выполняет предварительную выборку связанных объектов, отсутствие значения для chunk_size приведет к тому, что Django будет использовать неявное значение по умолчанию 2000, значение, полученное из a calculation on the psycopg mailing list:

Предполагая, что строки из 10-20 столбцов содержат смесь текстовых и числовых данных, 2000 будет собирать данные размером менее 100 КБ, что представляется хорошим компромиссом между количеством переданных строк и данными, отброшенными, если цикл завершается досрочно.

latest()

latest(*fields)
alatest(*fields)

Асинхронная версия: alatest()

Возвращает последний объект в таблице на основе заданных полей.

Этот пример возвращает последний Entry в таблице, согласно полю pub_date:

Entry.objects.latest('pub_date')

Вы также можете выбрать последнюю версию на основе нескольких полей. Например, чтобы выбрать Entry с самым ранним expire_date, когда две записи имеют одинаковое pub_date:

Entry.objects.latest('pub_date', '-expire_date')

Отрицательный знак в '-expire_date' означает сортировку expire_date в обратном порядке. Поскольку latest() получает последний результат, выбирается Entry с самым ранним expire_date.

Если ваша модель Meta указывает get_latest_by, вы можете опустить любые аргументы для earliest() или latest(). Поля, указанные в get_latest_by, будут использоваться по умолчанию.

Например get(), earliest() и latest() вызывают DoesNotExist, если нет объекта с данными параметрами.

Обратите внимание, что earliest() и latest() существуют исключительно для удобства и читабельности.

earliest() и latest() могут возвращать экземпляры с нулевыми датами.

Поскольку порядок делегирования в базе данных, результаты в полях, которые допускают нулевые значения, могут быть упорядочены по-разному, если вы используете разные базы данных. Например, PostgreSQL и MySQL сортируют нулевые значения, как будто они выше ненулевых значений, в то время как SQLite делает обратное.

Вы можете отфильтровать нулевые значения:

Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
Changed in Django 4.1:

Был добавлен метод alatest().

earliest()

earliest(*fields)
aearliest(*fields)

Асинхронная версия: aearliest()

Работает также как и latest() за исключением изменения направления.

Changed in Django 4.1:

Был добавлен метод aearliest().

first()

first()
afirst()

Асинхронная версия: afirst()

Возвращает первый объект, соответствующий запросу, или None, если нет соответствующего объекта. Если QuerySet не имеет определенного порядка, то набор запросов автоматически упорядочивается по первичному ключу. Это может повлиять на результаты агрегации, как описано в Взаимодействие с order_by().

Пример:

p = Article.objects.order_by('title', 'pub_date').first()

Обратите внимание, что first() является вспомогательным методом, следующий пример кода эквивалентен приведенному выше примеру:

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None
Changed in Django 4.1:

Был добавлен метод afirst().

last()

last()
alast()

Асинхронная версия: alast()

Работает как first(), но возвращает последний объект в наборе запросов.

Changed in Django 4.1:

Был добавлен метод alast().

aggregate()

aggregate(*args, **kwargs)
aaggregate(*args, **kwargs)

Асинхронная версия: aaggregate()

Возвращает словарь агрегированных значений (средние, суммы и т.д.), рассчитанных по QuerySet. Каждый аргумент aggregate() указывает значение, которое будет включено в возвращаемый словарь.

Функции агрегации, предоставляемые Django, описаны в Функции агрегации ниже. Поскольку агрегаты также являются выражениями запросов, вы можете комбинировать агрегаты с другими агрегатами или значениями для создания сложных агрегатов.

Агрегаты, указанные с использованием аргументов ключевого слова, будут использовать ключевое слово в качестве имени для аннотации. Для анонимных аргументов будет создано имя, основанное на имени агрегирующей функции и агрегируемого поля модели. Сложные агрегаты не могут использовать анонимные аргументы и должны указывать ключевое слово аргумент в качестве псевдонима.

Например, когда вы работаете с записями в блоге, вы можете узнать количество авторов, которые предоставили записи в блоге:

>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}

Используя аргумент ключевого слова для указания функции агрегирования, вы можете контролировать имя возвращаемого значения агрегации:

>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}

Подробное обсуждение агрегации смотрите в руководство по агрегации.

Changed in Django 4.1:

Был добавлен метод aaggregate().

exists()

exists()
aexists()

Асинхронная версия: aexists()

Возвращает True, если QuerySet содержит какие-либо результаты, и False, если нет. Он пытается выполнить запрос самым простым и быстрым способом, но он выполняет почти тот же запрос, что и обычный QuerySet.

exists() полезен для поиска, связанного с существованием каких-либо объектов в QuerySet, особенно в контексте большого QuerySet.

Чтобы узнать, содержит ли набор запросов какие-либо элементы:

if some_queryset.exists():
    print("There is at least one object in some_queryset")

Который будет быстрее, чем

if some_queryset:
    print("There is at least one object in some_queryset")

… но не в значительной степени (следовательно, для повышения эффективности требуется большой набор запросов).

Кроме того, если some_queryset еще не был проанализирован, но вы знаете, что это произойдет в какой-то момент, то использование some_queryset.exists() сделает более общую работу (один запрос для проверки существования плюс дополнительный для последующего извлечения результатов), а не просто bool(some_queryset), который извлекает результаты и затем проверяет, были ли какие-либо возвращены.

Changed in Django 4.1:

Был добавлен метод aexists().

contains()

contains(obj)
acontains(obj)

Асинхронная версия: acontains()

New in Django 4.0.

Возвращает True, если QuerySet содержит obj, и False, если нет. При этом делается попытка выполнить запрос самым простым и быстрым способом.

contains() полезен для проверки принадлежности объекта к QuerySet, особенно в контексте большого QuerySet.

Чтобы проверить, содержит ли набор запросов определенный элемент, выполните следующие действия:

if some_queryset.contains(obj):
    print('Entry contained in queryset')

Это будет быстрее, чем следующий способ, который требует оценки и итерации по всему набору запросов:

if obj in some_queryset:
    print('Entry contained in queryset')

Как и exists(), если some_queryset еще не был оценен, но вы знаете, что он будет оценен в какой-то момент, то при использовании some_queryset.contains(obj) будет сделан дополнительный запрос к базе данных, что в целом приведет к снижению общей производительности.

Changed in Django 4.1:

Был добавлен метод acontains().

update()

update(**kwargs)
aupdate(**kwargs)

Асинхронная версия: aupdate()

Выполняет запрос на обновление SQL для указанных полей и возвращает количество совпадающих строк (которое может не совпадать с количеством обновленных строк, если некоторые строки уже имеют новое значение).

Например, чтобы отключить комментарии для всех записей блога, опубликованных в 2010 году, вы можете сделать это:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

(Предполагается, что ваша модель Entry имеет поля pub_date и comments_on.)

Вы можете обновить несколько полей - нет ограничений на их количество. Например, здесь мы обновляем поля comments_on и headline:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')

Метод update() применяется мгновенно, и единственное ограничение на обновляемый QuerySet заключается в том, что он может обновлять только столбцы в основной таблице модели, но не в связанных моделях. Вы не можете сделать так, например:

>>> Entry.objects.update(blog__name='foo') # Won't work!

Фильтрация на основе связанных полей все еще возможна, хотя:

>>> Entry.objects.filter(blog__id=1).update(comments_on=True)

Вы не можете вызвать update() для QuerySet, у которого был взят фрагмент или который больше не может быть отфильтрован.

Метод update() возвращает количество затронутых строк:

>>> Entry.objects.filter(id=64).update(comments_on=True)
1

>>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
0

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132

Если вы просто обновляете запись и вам не нужно ничего делать с объектом модели, наиболее эффективным подходом является вызов update() вместо загрузки объекта модели в память. Например, вместо этого:

e = Entry.objects.get(id=10)
e.comments_on = False
e.save()

…сделайте это:

Entry.objects.filter(id=10).update(comments_on=False)

Использование update() также предотвращает состояние гонки, при котором что-то может измениться в вашей базе данных за короткий промежуток времени между загрузкой объекта и вызовом save().

Наконец, следует понимать, что update() выполняет обновление на уровне SQL и, таким образом, не вызывает никаких методов save() в ваших моделях и не генерирует pre_save или post_save (которые являются следствием вызова Model.save() <django.db.models.Model.save> `). Если вы хотите обновить группу записей для модели, имеющей пользовательский метод :meth:`~django.db.models.Model.save(), выполните их в цикле и вызовите save(), как тут:

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()
Changed in Django 4.1:

Был добавлен метод aupdate().

Сортировка набора

Связь order_by() с update() поддерживается только в MariaDB и MySQL и игнорируется для других баз данных. Это полезно для обновления уникального поля в указанном порядке без конфликтов. Например:

Entry.objects.order_by('-number').update(number=F('number') + 1)

Примечание

Предложение order_by() будет проигнорировано, если оно содержит аннотации, наследуемые поля или поиск, охватывающий отношения.

delete()

delete()
adelete()

Асинхронная версия: adelete()

Выполняет запрос на удаление SQL для всех строк в QuerySet и возвращает количество удаленных объектов и словарь с количеством удалений на тип объекта.

delete() применяется мгновенно. Вы не можете вызвать delete() для QuerySet, у которого был взят фрагмент или который больше не может быть отфильтрован.

Например, чтобы удалить все записи в определенном блоге:

>>> b = Blog.objects.get(pk=1)

# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})

По умолчанию класс Django ForeignKey эмулирует ограничение SQL ON DELETE CASCADE - другими словами, любые объекты с внешними ключами, указывающими на объекты, которые будут удалены, будут удалены вместе с ними. Например:

>>> blogs = Blog.objects.all()

# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})

Это каскадное поведение настраивается с помощью аргумента on_delete для ForeignKey.

Метод delete() выполняет массовое удаление и не вызывает никаких методов delete() в ваших моделях. Однако он генерирует сигналы pre_delete и post_delete для всех удаленных объектов (включая каскадные удаления).

Django должен извлекать объекты в память для отправки сигналов и обработки каскадов. Однако, если нет каскадов и нет сигналов, тогда Django может использовать ускоренный путь и удалять объекты без загрузки в память. Для больших удалений это может привести к значительному сокращению использования памяти. Количество выполненных запросов также может быть уменьшено.

Внешние ключи, для которых установлено on_delete DO_NOTHING, не мешают использовать быстрый путь при удалении.

Обратите внимание, что запросы, сгенерированные при удалении объекта, являются деталями реализации, которые могут быть изменены.

Changed in Django 4.1:

Был добавлен метод adelete().

as_manager()

classmethod as_manager()

Метод класса, который возвращает экземпляр Manager с копией методов QuerySet. Смотрите create-manager-with-queryset-method для более подробной информации.

Обратите внимание, что в отличие от других записей в этом разделе, эта не имеет асинхронного варианта, поскольку она не выполняет запрос.

explain()

explain(format=None, **options)
aexplain(format=None, **options)

Асинхронная версия: aexplain()

Возвращает строку плана выполнения QuerySet, в которой подробно описывается, как база данных будет выполнять запрос, включая любые индексы или объединения, которые будут использоваться. Знание этих деталей может помочь вам повысить производительность медленных запросов.

Например, при использовании PostgreSQL:

>>> print(Blog.objects.filter(title='My Blog').explain())
Seq Scan on blog  (cost=0.00..35.50 rows=10 width=12)
  Filter: (title = 'My Blog'::bpchar)

Вывод значительно различается между базами данных.

explain() поддерживается всеми встроенными базами данных базы данных, кроме Oracle, потому что реализация там не проста.

Параметр format изменяет формат вывода по умолчанию для баз данных, который обычно является текстовым. PostgreSQL поддерживает форматы 'TEXT', 'JSON', 'YAML' и 'XML'. MariaDB и MySQL поддерживают форматы 'TEXT' (также называемые 'TRADITIONAL') и 'JSON'. MySQL 8.0.16+ также поддерживает улучшенный формат 'TREE', который похож на вывод 'TEXT' PostgreSQL и используется по умолчанию, если поддерживается.

Некоторые базы данных принимают флаги, которые могут возвращать больше информации о запросе. Передайте эти флаги в качестве ключевых аргументов. Например, при использовании PostgreSQL:

>>> print(Blog.objects.filter(title='My Blog').explain(verbose=True, analyze=True))
Seq Scan on public.blog  (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
  Output: id, title
  Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms

В некоторых базах данных флаги могут привести к выполнению запроса, что может отрицательно повлиять на вашу базу данных. Например, флаг ANALYZE, поддерживаемый MariaDB, MySQL 8.0.18+ и PostgreSQL, может привести к изменениям данных, если есть триггеры или если вызывается функция, даже для запроса SELECT.

Changed in Django 4.1:

Был добавлен метод aexplain().

Поиск Field

Поиск по полю - это то, как вы определяете содержание предложения SQL WHERE. Они указываются в качестве аргументов ключевых слов для методов QuerySet filter(), exclude() и get().

Для ознакомления смотрите документация по моделям и запросам к базе данных.

Встроенные в Django поиски перечислены ниже. Также возможно написать собственные поиски для полей модели.

Для удобства, когда не указан тип поиска (как в Entry.objects.get(id=14)), предполагается, что тип поиска exact.

exact

Точное совпадение. Если значение, предоставленное для сравнения, равно None, оно будет интерпретировано как SQL NULL (подробнее см. isnull).

Примеры:

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

SQL-эквивалент:

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

MySQL сравнения

В MySQL настройка «collation» таблицы базы данных определяет, являются ли exact сравнения чувствительными к регистру. Это настройка базы данных, а не настройка Django. Можно настроить ваши таблицы MySQL для использования чувствительных к регистру сравнений, но здесь есть некоторые компромиссы. Для получения дополнительной информации об этом смотрите раздел collation в документации базы данных.

iexact

Точное совпадение без учета регистра. Если значение, предоставленное для сравнения, равно None, оно будет интерпретировано как SQL NULL (подробнее смотрите isnull).

Пример:

Blog.objects.get(name__iexact='beatles blog')
Blog.objects.get(name__iexact=None)

SQL-эквивалент:

SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;

Обратите внимание, что первый запрос будет соответствовать 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG' и т.д.

Пользователи SQLite

При использовании бэкэнда SQLite и строк, не относящихся к ASCII, помните про примечание к базе данных о сравнении строк. SQLite не выполняет сопоставление без учета регистра для не-ASCII-строк.

contains

Чувствительный к регистру тест сдерживания.

Пример:

Entry.objects.get(headline__contains='Lennon')

SQL-эквивалент:

SELECT ... WHERE headline LIKE '%Lennon%';

Обратите внимание, что это будет соответствовать заголовку 'Lennon honored today' но не 'lennon honored today'.

Пользователи SQLite

SQLite не поддерживает чувствительные к регистру операторы LIKE; contains действует как icontains для SQLite. Смотрите примечание к базе данных для получения дополнительной информации.

icontains

Нечувствительное к регистру .

Пример:

Entry.objects.get(headline__icontains='Lennon')

SQL-эквивалент:

SELECT ... WHERE headline ILIKE '%Lennon%';

Пользователи SQLite

При использовании бэкэнда SQLite и строк, не относящихся к ASCII, помните про примечание к базе данных о сравнении строк.

in

В данной итерации часто список, кортеж или набор запросов. Это не обычный случай использования, но строки (будучи итеративными) принимаются.

Примеры:

Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')

SQL-эквивалент:

SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');

Вы также можете использовать набор запросов для динамической оценки списка значений вместо предоставления списка литеральных значений:

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

Этот набор запросов будет оцениваться как оператор подвыбора:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

Если вы передаете QuerySet, полученный в результате values() или values_list(), в качестве значения для поиска __in, вам нужно убедиться, что вы извлекаете только одно поле в результат. Например, это будет работать (фильтрация по именам блогов):

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Этот пример вызовет исключение, поскольку внутренний запрос пытается извлечь два значения поля, где ожидается только одно:

# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Вопросы производительности

Будьте осторожны с использованием вложенных запросов и понимайте характеристики производительности сервера базы данных (если сомневаетесь, тестируйте!). Некоторые бэкэнды базы данных, особенно MySQL, не очень хорошо оптимизируют вложенные запросы. В этих случаях более эффективно извлечь список значений и затем передать его во второй запрос. То есть выполнить два запроса вместо одного:

values = Blog.objects.filter(
        name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))

Обратите внимание на вызов list() вокруг блога QuerySet для принудительного выполнения первого запроса. Без него будет выполнен вложенный запрос, потому что `` QuerySet`` - ленивые.

gt

Больше чем.

Пример:

Entry.objects.filter(id__gt=4)

SQL-эквивалент:

SELECT ... WHERE id > 4;

gte

Больше или равно.

lt

Меньше, чем.

lte

Меньше или равно.

startswith

Начинается с (с учетом регистра).

Пример:

Entry.objects.filter(headline__startswith='Lennon')

SQL-эквивалент:

SELECT ... WHERE headline LIKE 'Lennon%';

SQLite не поддерживает чувствительные к регистру операторы LIKE; startswith действует как istartswith для SQLite.

istartswith

Начинается с (без учета регистра).

Пример:

Entry.objects.filter(headline__istartswith='Lennon')

SQL-эквивалент:

SELECT ... WHERE headline ILIKE 'Lennon%';

Пользователи SQLite

При использовании бэкэнда SQLite и строк, не относящихся к ASCII, помните про примечание к базе данных о сравнении строк.

endswith

Заканчивается на (с учетом регистра).

Пример:

Entry.objects.filter(headline__endswith='Lennon')

SQL-эквивалент:

SELECT ... WHERE headline LIKE '%Lennon';

Пользователи SQLite

SQLite не поддерживает чувствительные к регистру операторы LIKE; endswith действует как iendswith для SQLite. Для получения дополнительной информации обратитесь к документации замечания к базе данных.

iendswith

Заканчивается на (без учета регистра).

Пример:

Entry.objects.filter(headline__iendswith='Lennon')

SQL-эквивалент:

SELECT ... WHERE headline ILIKE '%Lennon'

Пользователи SQLite

При использовании бэкэнда SQLite и строк, не относящихся к ASCII, помните про примечание к базе данных о сравнении строк.

range

Диапазон проверки (включительно).

Пример:

import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL-эквивалент:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

Вы можете использовать range везде, где можете использовать BETWEEN в SQL - для дат, чисел и даже символов.

Предупреждение

Фильтрация DateTimeField с датами не будет включать элементы в последний день, потому что границы интерпретируются как «0:00 на данную дату». Если бы pub_date был DateTimeField, вышеприведенное выражение превратилось бы в этот SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';

Вообще говоря, вы не можете смешивать даты и время.

date

Для полей даты и времени преобразует значение как дату. Позволяет цепочки дополнительных поисков по полям. Принимает значение даты.

Пример:

Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)

Когда USE_TZ равно True, поля преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

year

Для полей даты и даты и времени точное совпадение года. Позволяет цепочки дополнительных поисков по полям. Принимает целое число - год.

Пример:

Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)

SQL-эквивалент:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

iso_year

Для полей даты и даты и времени точно указан год недели с номером нумерации ISO 8601. Позволяет цепочки дополнительных полевых поисков. Принимает целое число - год

Пример:

Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

month

Для полей даты и даты и времени точное совпадение месяцев. Позволяет цепочки дополнительных поисков по полям. Принимает целое число от 1 (январь) до 12 (декабрь).

Пример:

Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)

SQL-эквивалент:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

day

Для полей даты и даты и времени - точное совпадение дня. Позволяет цепочки дополнительных поисков по полям. Принимает целое число - день.

Пример:

Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)

SQL-эквивалент:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Обратите внимание, что это будет соответствовать любой записи с pub_date в третий день месяца, например 3 января, 3 июля и т.д.

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

week

Для полей даты и даты и времени возвращает номер недели (1-52 или 53) в соответствии с ISO-8601 <https://en.wikipedia.org/wiki/ISO-8601> _, то есть недели, начинающиеся в понедельник и первая неделя содержит первый четверг года.

Пример:

Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)

(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

week_day

Для полей даты и даты и времени соответствует «день недели». Позволяет цепочки дополнительных поисков.

Принимает целочисленное значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).

Пример:

Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)

(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)

Обратите внимание, что это будет соответствовать любой записи с pub_date, которая выпадает на понедельник (2-ой день недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются, причем день 1 - воскресенье, а день 7 - суббота.

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

iso_week_day

Для полей даты и даты-времени точный день недели соответствует ISO 8601. Позволяет цепочки дополнительных поисков.

Принимает целочисленное значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).

Пример:

Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)

(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)

Обратите внимание, что это будет соответствовать любой записи с pub_date, которая выпадает на понедельник (1-й день недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются, причем день 1 - понедельник, а день 7 - воскресенье.

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

quarter

Для полей даты и даты и времени соответствующий квартал года. Позволяет цепочки дополнительных поисков. Принимает целое значение от 1 до 4, представляющее квартал года.

Пример получения записей во втором квартале (с 1 апреля по 30 июня):

Entry.objects.filter(pub_date__quarter=2)

(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

time

Для полей даты и времени преобразует значение как время. Позволяет цепочки дополнительных поисков. Принимает значение datetime.time.

Пример:

Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))

(Эквивалентный фрагмент кода SQL для этого поиска не включен, поскольку реализация соответствующего запроса варьируется в зависимости от разных механизмов баз данных.)

Когда USE_TZ равно True, поля преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

hour

Для полей даты и времени точное совпадение часов. Позволяет цепочки дополнительных поисков. Принимает целое число от 0 до 23.

Пример:

Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)

SQL-эквивалент:

SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

minute

Для полей даты и времени, точное совпадение минут. Позволяет цепочки дополнительных поисков. Принимает целое число от 0 до 59.

Пример:

Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)

SQL-эквивалент:

SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

second

Для полей даты и времени точное совпадение секунд. Позволяет цепочки дополнительных поисков. Принимает целое число от 0 до 59.

Пример:

Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)

SQL-эквивалент:

SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';

(Точный синтаксис SQL варьируется для каждого механизма базы данных.)

Когда USE_TZ равно True, поля даты и времени преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуется определение часовых поясов в базе данных.

isnull

Принимает True или False, которые соответствуют SQL-запросам IS NULL и IS NOT NULL, соответственно.

Пример:

Entry.objects.filter(pub_date__isnull=True)

SQL-эквивалент:

SELECT ... WHERE pub_date IS NULL;

regex

Чувствительное к регистру совпадение регулярного выражения.

Синтаксис регулярного выражения - это используемый серверный компонент базы данных. В случае SQLite, который не имеет встроенной поддержки регулярных выражений, эта функция обеспечивается пользовательской функцией REGEXP (Python), поэтому синтаксис регулярного выражения является синтаксисом модуля re в Python.

Пример:

Entry.objects.get(title__regex=r'^(An?|The) +')

SQL-эквивалент:

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

Рекомендуется использовать необработанные строки (например, r'foo' вместо 'foo') для передачи синтаксиса регулярного выражения.

iregex

Нечувствительное к регистру совпадение регулярного выражения.

Пример:

Entry.objects.get(title__iregex=r'^(an?|the) +')

SQL-эквивалент:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

Агрегационные функции

Django предоставляет следующие функции агрегирования в модуле django.db.models. Подробнее о том, как использовать эти агрегатные функции, смотрите руководство по агрегации тем. Обратитесь к документации Aggregate, чтобы узнать, как создавать агрегаты.

Предупреждение

SQLite не может обрабатывать агрегирование полей даты/времени «из коробки». Это связано с тем, что в SQLite нет собственных полей даты и времени, а Django в настоящее время эмулирует эти функции с помощью текстового поля. Попытки использовать агрегирование полей даты/времени в SQLite вызовут NotSupportedError.

Примечание

Функции агрегации возвращают None при использовании с пустым QuerySet. Например, агрегатная функция Sum возвращает None вместо 0, если QuerySet не содержит записей. Чтобы вместо этого вернуть другое значение, передайте значение в аргумент default. Исключением является Count, который возвращает 0, если QuerySet пуст. Count не поддерживает аргумент default.

Все агрегаты имеют следующие общие параметры:

expressions

Строки, которые ссылаются на поля в модели, преобразования поля или выражения запроса.

output_field

Необязательный аргумент, представляющий поле модели возвращаемого значения

Примечание

При объединении нескольких типов полей Django может определить output_field, только если все поля одного типа. В противном случае вы должны предоставить output_field самостоятельно.

filter

Необязательный Q object, который используется для фильтрации агрегируемых строк.

Смотрите Условная агрегация и :ref:`filtering-on-annotations`ю

default

New in Django 4.0.

Необязательный аргумент, который позволяет указать значение, используемое в качестве значения по умолчанию, когда набор запросов (или группировка) не содержит записей.

**extra

Аргументы ключевых слов, которые могут предоставить дополнительный контекст для SQL, сгенерированного агрегатом.

Avg

class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[исходный код]

Возвращает среднее значение заданного выражения, которое должно быть числовым, если вы не укажете другое output_field.

  • Псевдоним по умолчанию: <field>__avg
  • Тип возвращаемого значения: float, если на входе int, в остальном то же самое, что и поле ввода, или output_field, если он указан
distinct

Необязательно. Если distinct=True, Avg возвращает среднее значение уникальных значений. Это SQL-эквивалент AVG(DISTINCT <field>). По умолчанию используется значение False.

Count

class Count(expression, distinct=False, filter=None, **extra)[исходный код]

Возвращает количество объектов, связанных через предоставленное выражение.

  • Псевдоним по умолчанию: <field>__count
  • Тип возврата: `` int``
distinct

Необязательно. Если distinct=True, подсчет будет включать только уникальные экземпляры. Это SQL-эквивалент значения COUNT(DISTINCT <field>). По умолчанию используется значение False.

Примечание

Аргумент default не поддерживается.

Max

class Max(expression, output_field=None, filter=None, default=None, **extra)[исходный код]

Возвращает максимальное значение данного выражения.

  • Псевдоним по умолчанию: <field>__max
  • Тип возвращаемого значения: такой же, как у поля ввода, или output_field, если указано

Min

class Min(expression, output_field=None, filter=None, default=None, **extra)[исходный код]

Возвращает минимальное значение данного выражения.

  • Псевдоним по умолчанию: <field>__min
  • Тип возвращаемого значения: такой же, как у поля ввода, или output_field, если указано

StdDev

class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)[исходный код]

Возвращает стандартное отклонение данных в предоставленном выражении.

  • Псевдоним по умолчанию: <field>__stddev
  • Тип возвращаемого значения: float, если на входе int, в остальном то же самое, что и поле ввода, или output_field, если он указан
sample

Необязательно. По умолчанию StdDev возвращает популяционное стандартное отклонение. Однако, если sample=True, возвращаемое значение будет выборочным стандартным отклонением.

Sum

class Sum(expression, output_field=None, distinct=False, filter=None, default=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, default=None, **extra)[исходный код]

Возвращает дисперсию данных в предоставленном выражении.

  • Псевдоним по умолчанию: <field>__variance
  • Тип возвращаемого значения: float, если на входе int, в остальном то же самое, что и поле ввода, или output_field, если он указан
sample

Необязательно. По умолчанию Variance возвращает дисперсию популяции. Однако, если sample=True, возвращаемое значение будет дисперсией выборки.

Вернуться на верх