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

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

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

Когда QuerySetоцениваются s

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

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

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

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

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

  • Нарезка. Как объяснено в разделе Ограничение QuerySets , a QuerySetможно нарезать, используя синтаксис нарезки массива Python. Нарезка неоцененного QuerySetобычно возвращает другое неоцененное QuerySet, но Django выполнит запрос к базе данных, если вы используете параметр «шаг» синтаксиса фрагмента, и вернет список. Нарезка QuerySet, который был оценен, также возвращает список.

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

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

  • repr (). A QuerySetоценивается, когда вы его вызываете repr(). Это сделано для удобства в интерактивном интерпретаторе Python, чтобы вы могли сразу увидеть свои результаты при интерактивном использовании API.

  • len (). A QuerySetоценивается, когда вы его вызываете len(). Это, как и следовало ожидать, возвращает длину списка результатов.

    Примечание. Если вам нужно только определить количество записей в наборе (и не нужны фактические объекты), гораздо эффективнее обрабатывать счет на уровне базы данных с помощью SQL . Django предоставляет метод именно по этой причине.SELECT COUNT(*)count()

  • список(). Принудительная оценка объекта 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().

Травление QuerySets

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

Если вы хотите получить только необходимую информацию для воссоздания QuerySetиз базы данных позже, выберите queryатрибут файла QuerySet. Затем вы можете воссоздать оригинал QuerySet(без загрузки каких-либо результатов), используя следующий код:

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

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

Ограничения на QuerySet.values_list()

Если вы воссоздадите QuerySet.values_list()с использованием query атрибута pickled , он будет преобразован в 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'}]>

Вы не можете делиться огурцами между версиями

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

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

QuerySetAPI

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

classQuerySet ( model = None , query = None , using = None , hints = None )

Обычно, когда вы взаимодействуете с, QuerySetвы используете его, объединяя фильтры . Чтобы это работало, большинство QuerySetметодов возвращают новые наборы запросов. Эти методы подробно рассматриваются далее в этом разделе.

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

ordered

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

db

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

Примечание

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

Методы, возвращающие новый QuerySets

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

filter()

filter( ** kwargs )

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

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

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

exclude()

exclude( ** kwargs )

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

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

В этом примере исключаются все записи, которые pub_dateстарше 2005-1-3 И у которых headlineесть «Привет»:

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 ИЛИ с заголовком «Привет»:

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

annotate()

annotate( * аргументы , ** 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( * аргументы , ** kwargs )
Новое в Django 3.2.

То же, что 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( * поля )

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

Пример:

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

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

Entry.objects.order_by('?')

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

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

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

Если вы попытаетесь упорядочить по полю, которое связано с другой моделью, Django будет использовать порядок по умолчанию для связанной модели или по первичному ключу связанной модели, если он не Meta.orderingуказан. Например, поскольку для Blog модели не указан порядок по умолчанию:

Entry.objects.order_by('blog')

… Идентично:

Entry.objects.order_by('blog__id')

Если бы это Blogбыло так , то первый набор запросов был бы идентичен:ordering = ['name']

Entry.objects.order_by('blog__name')

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

Entry.objects.order_by(Coalesce('summary', 'headline').desc())

asc()и desc()имеют аргументы ( nulls_firstи nulls_last), управляющие сортировкой нулевых значений.

Будьте осторожны при сортировке по полям в связанных моделях, если вы также используете distinct(). См. Примечание в distinct()для объяснения того, как упорядочение связанных моделей может изменить ожидаемые результаты.

Примечание

Допускается указывать многозначное поле для упорядочивания результатов (например, ManyToManyFieldполе или обратная связь ForeignKeyполя).

Рассмотрим этот случай:

class Event(Model):
   parent = models.ForeignKey(
       'self',
       on_delete=models.CASCADE,
       related_name='children',
   )
   date = models.DateField()

Event.objects.order_by('children__date')

Здесь потенциально может быть несколько данных для заказа для каждого Event; каждый Eventс несколькими childrenбудет возвращен несколько раз в новый, QuerySetкоторый order_by()создает. Другими словами, использование order_by()в QuerySetможет вернуть больше элементов, чем вы работали с самого начала, что, вероятно, не является ни ожидаемым, ни полезным.

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

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

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

Entry.objects.order_by(Lower('headline').desc())

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

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

Каждый order_by()вызов очищает все предыдущие заказы. Например, этот запрос будет отсортирован по, pub_dateа не по headline:

Entry.objects.order_by('headline').order_by('pub_date')

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

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

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

reverse()

reverse()

Используйте этот reverse()метод, чтобы изменить порядок, в котором возвращаются элементы набора запросов. Повторный вызов reverse()восстанавливает порядок в нормальном направлении.

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

my_queryset.reverse()[:5]

Обратите внимание, что это не совсем то же самое, что нарезка с конца последовательности в Python. В приведенном выше примере сначала будет возвращен последний элемент, затем предпоследний элемент и так далее. Если бы у нас была последовательность Python и seq[-5:]мы бы посмотрели, мы бы сначала увидели пятый-последний элемент. Django не поддерживает этот режим доступа (разрезание с конца), потому что в SQL невозможно сделать это эффективно.

Также обратите внимание, что reverse()обычно следует вызывать только для того, QuerySet который имеет определенный порядок (например, при запросе к модели, которая определяет порядок по умолчанию, или при использовании order_by()). Если такой порядок не определен для данного QuerySetобъекта, его вызов reverse()не имеет реального эффекта (порядок не был определен до вызова reverse()и останется неопределенным после этого).

distinct()

distinct( * поля )

Возвращает новый, QuerySetкоторый используется в своем SQL-запросе. Это исключает повторяющиеся строки из результатов запроса.SELECT DISTINCT

По умолчанию a QuerySetне удаляет повторяющиеся строки. На практике это редко является проблемой, потому что простые запросы, такие как Blog.objects.all() не создают возможности дублирования строк результатов. Однако, если ваш запрос охватывает несколько таблиц, при QuerySetоценке a можно получить повторяющиеся результаты . Вот когда вы бы использовали distinct().

Примечание

Любые поля, используемые в order_by()вызове, включаются в SELECTстолбцы SQL . Иногда это может привести к неожиданным результатам при использовании вместе с distinct(). Если вы упорядочиваете по полям из связанной модели, эти поля будут добавлены к выбранным столбцам, и в противном случае повторяющиеся строки могут выглядеть разными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они нужны только для поддержки упорядочения), иногда кажется, что возвращаются неотличимые результаты.

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

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

Только в PostgreSQL вы можете передавать позиционные аргументы ( *fields), чтобы указать имена полей, к которым DISTINCTдолжен применяться. Это переводится в SQL-запрос. Вот в чем разница. При обычном вызове база данных сравнивает каждое поле в каждой строке, чтобы определить, какие строки являются разными. Для вызова с указанными именами полей база данных будет сравнивать только указанные имена полей.SELECT DISTINCT ONdistinct()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 ONORDER BYBlogorderingname

Entry.objects.order_by('blog').distinct('blog')

… Не будет работать, потому что запрос будет упорядочен, blog__nameтаким образом, не совпадая с выражением. Вам нужно будет явно упорядочить по полю отношения ( в данном случае) или по указанному ( ), чтобы убедиться, что оба выражения совпадают.DISTINCT ON_idblog_idblog__pk

values()

values( * поля , ** выражения )

Возвращает, 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}]>

Несколько тонкостей, о которых стоит упомянуть:

  • Если у вас есть поле с именем fooa ForeignKey, values()вызов по умолчанию вернет названный ключ словаря foo_id, поскольку это имя скрытого атрибута модели, в котором хранится фактическое значение ( foo атрибут относится к связанной модели). Когда вы вызываете values()и передаете имена полей, вы можете передать либо foo или, foo_idи вы получите то же самое (ключ словаря будет соответствовать имени поля, которое вы передали).

    Например:

    >>> Entry.objects.values()
    <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
    
    >>> Entry.objects.values('blog')
    <QuerySet [{'blog': 1}, ...]>
    
    >>> Entry.objects.values('blog_id')
    <QuerySet [{'blog_id': 1}, ...]>
    
  • При использовании values()вместе с distinct()помните, что порядок может повлиять на результаты. Подробности см. В примечании distinct().

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

  • Колл only()и defer()после values()не имеет смысла, так что это поднимет TypeError.

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

    >>> from django.db.models import CharField, Count
    >>> from django.db.models.functions import Lower
    >>> CharField.register_lookup(Lower)
    >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry'))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    >>> Blog.objects.values(
    ...     entry__authors__name__lower=Lower('entry__authors__name')
    ... ).annotate(entries=Count('entry'))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    >>> Blog.objects.annotate(
    ...     entry__authors__name__lower=Lower('entry__authors__name')
    ... ).values('entry__authors__name__lower').annotate(entries=Count('entry'))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    

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

Наконец, обратите внимание , что вы можете позвонить filter(), order_by()и т.д. после values()вызова, это означает , что эти два вызова идентичны:

Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()

Люди, создавшие Django, предпочитают сначала ставить все методы, влияющие на SQL, а затем (необязательно) любые методы, влияющие на вывод (например, values()), но на самом деле это не имеет значения. Это ваш шанс по-настоящему продемонстрировать свой индивидуализм.

Вы также можете обратиться к полям по соответствующим моделям с обратными отношениями пути OneToOneField, ForeignKeyи ManyToManyFieldатрибутами:

>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
     {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>

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

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

Логические значения для JSONFieldSQLite

Благодаря тому , как JSON_EXTRACTфункция SQL реализован на SQLite, values()будет возвращаться 1и 0вместо того , чтобы Trueи False для JSONFieldключевых преобразований.

values_list()

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

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

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

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

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

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

Это ошибка, flatесли имеется более одного поля.

Вы можете пройти, named=Trueчтобы получить результаты как namedtuple():

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

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

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

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

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

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

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

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

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

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

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

Логические значения для JSONFieldSQLite

Благодаря тому , как JSON_EXTRACTфункция SQL реализован на SQLite, values_list()будет возвращаться 1и 0вместо того , чтобы Trueи Falseдля JSONFieldключевых преобразований.

dates()

dates( поле , вид , порядок = '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( имя_поля , вид , порядок = 'ASC' , tzinfo = Нет , is_dst = Нет )

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

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

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

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

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

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

Новое в Django 3.1:

is_dstПараметр был добавлен.

Примечание

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

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подкласса). Это может быть полезно в ситуациях, когда вы, возможно, захотите передать либо менеджер модели, либо a QuerySetи выполнить дальнейшую фильтрацию результата. После вызова all()любого объекта вам определенно придется QuerySetпоработать.

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

union()

union( * Other_qs , все = False )

Использует оператор SQL UNIONдля объединения результатов двух или более QuerySets. Например:

>>> qs1.union(qs2, qs3)

По UNIONумолчанию оператор выбирает только отдельные значения. Чтобы разрешить повторяющиеся значения, используйте all=Trueаргумент.

union(), intersection(), И difference()возвращение модель экземпляры типа первый , QuerySetдаже если аргументы QuerySets других моделей. Передача разных моделей работает до тех пор, пока SELECTсписок один и тот же во всех QuerySets (по крайней мере, типы, имена не имеют значения, если типы находятся в одном порядке). В таких случаях вы должны использовать имена столбцов из первых 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 BYcount()exists()order_by()values()values_list()QuerySetLIMITOFFSET

intersection()

intersection( * other_qs )

Использует оператор SQL INTERSECTдля возврата общих элементов двух или более QuerySets. Например:

>>> qs1.intersection(qs2, qs3)

См. union()Некоторые ограничения.

difference()

difference( * other_qs )

Использует оператор SQL, EXCEPTчтобы сохранить только элементы, присутствующие в, QuerySetно не в некоторых других QuerySet. Например:

>>> qs1.difference(qs2, qs3)

См. union()Некоторые ограничения.

extra()

extra( select = None , где = None , params = None , tables = None , order_by = None , select_params = None )

Иногда синтаксис запроса Django сам по себе не может легко выразить сложное WHEREпредложение. Для этих крайних случаев Django предоставляет extra() QuerySetмодификатор - ловушку для вставки определенных предложений в SQL, сгенерированный файлом QuerySet.

Используйте этот метод в крайнем случае

Это старый API, от которого мы намерены отказаться в какой-то момент в будущем. Используйте его только в том случае, если вы не можете выразить свой запрос с помощью других методов набора запросов. Если вам все же нужно его использовать, отправьте заявку, используя ключевое слово QuerySet.extra, и укажите в ней свой вариант использования (сначала проверьте список существующих заявок), чтобы мы могли улучшить QuerySet API и разрешить удаление extra(). Мы больше не улучшаем и не исправляем ошибки для этого метода.

Например, это использование extra():

>>> qs.extra(
...     select={'val': "select col from sometable where othercol = %s"},
...     select_params=(someparam,),
... )

эквивалентно:

>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

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

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

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

Вы также не должны заключать в кавычки заполнители в строке SQL. Этот пример уязвим для SQL-инъекции из-за кавычек %s:

SELECT col FROM sometable WHERE othercol = '%s'  # unsafe!

Вы можете узнать больше о том, как работает защита Django от SQL-инъекций .

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

Укажите один или несколько params, select, whereили tables. Ни один из аргументов не требуется, но вы должны использовать хотя бы один из них.

  • select

    selectАргумент позволяет поместить дополнительные поля в SELECT предложении. Это должен быть словарь, отображающий имена атрибутов для предложений SQL, чтобы использовать их для вычисления этого атрибута.

    Пример:

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

    В результате каждый Entryобъект будет иметь дополнительный атрибут, is_recentлогическое значение, указывающее, pub_date превышает ли запись значение 1 января 2006 г.

    Django вставляет данный фрагмент SQL непосредственно в SELECT оператор, поэтому результирующий SQL из приведенного выше примера будет примерно таким:

    SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
    FROM blog_entry;
    

    Следующий пример более сложный; он выполняет подзапрос, чтобы дать каждому результирующему Blogобъекту entry_countатрибут, целое число связанных Entryобъектов:

    Blog.objects.extra(
        select={
            'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
        },
    )
    

    В этом конкретном случае мы используем тот факт, что запрос уже содержит blog_blogтаблицу в своем FROMпредложении.

    Результирующий SQL в приведенном выше примере будет:

    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
    FROM blog_blog;
    

    Обратите внимание, что круглые скобки, необходимые для большинства движков баз данных вокруг подзапросов, не требуются в предложениях Django select. Также обратите внимание, что некоторые серверные части базы данных, такие как некоторые версии MySQL, не поддерживают подзапросы.

    В некоторых редких случаях может потребоваться передать параметры фрагментам SQL в формате extra(select=...). Для этого используйте select_paramsпараметр.

    Это будет работать, например:

    Blog.objects.extra(
        select={'a': '%s', 'b': '%s'},
        select_params=('one', 'two'),
    )
    

    Если вам нужно использовать литерал %sвнутри выбранной строки, используйте последовательность %%s.

  • where / tables

    Вы можете определить явные WHEREпредложения SQL - возможно, для выполнения неявных соединений - используя where. Вы можете вручную добавить таблицы в предложение SQL FROM, используя tables.

    whereи tablesоба берут список строк. Все where параметры объединяются «И» по отношению к любым другим критериям поиска.

    Пример:

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

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

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

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

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

  • order_by

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

    Например:

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

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

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

  • params

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

    Пример:

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

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

    Плохо:

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

    Хорошо:

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

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

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

defer()

defer( * поля )

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

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

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

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

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

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

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

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

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

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

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

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

Примечание

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

Даже если вы думаете, что находитесь в ситуации расширенного варианта использования, используйте defer () только тогда, когда вы не можете, во время загрузки набора запроса определить, понадобятся ли вам дополнительные поля или нет . Если вы часто загружаете и используете определенное подмножество данных, лучший выбор, который вы можете сделать, - это нормализовать свои модели и поместить незагруженные данные в отдельную модель (и таблицу базы данных). Если по какой-то причине столбцы должны оставаться в одной таблице, создайте модель с (см. Документацию), содержащую только поля, которые вам обычно нужно загрузить, и используйте их там, где вы могли бы в противном случае вызвать . Это делает ваш код более понятным для читателя, он работает немного быстрее и потребляет немного меньше памяти в процессе Python.Meta.managed = Falsemanaged attributedefer()

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

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

    class Meta:
        managed = False
        db_table = 'app_largetable'

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

    class Meta:
        db_table = 'app_largetable'

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

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

Примечание

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

only()

only( * поля )

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

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

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

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

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

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

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

# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")

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

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

Примечание

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

using()

using( псевдоним )

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

Например:

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

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

select_for_update()

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

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

Например:

from django.db import transaction

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

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

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

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

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

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

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

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

Вы не можете использовать select_for_update()отношения, допускающие значение NULL:

>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join

Чтобы избежать этого ограничения, вы можете исключить нулевые объекты, если они вам не нужны:

>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>

В настоящее время postgresql, oracleи mysqlдвижки баз данных поддержки select_for_update(). Тем не менее, MariaDB 10.3+ поддерживает только nowaitаргумент и MySQL 8.0.1+ поддерживает nowait, skip_lockedи ofаргументы. no_keyАргумент поддерживается только на PostgreSQL.

Переходя nowait=True, skip_locked=True, no_key=Trueили ofс select_for_update()помощью базы данных движков , которые не поддерживают эти параметры, такие как MySQL, поднимает NotSupportedError. Это предотвращает неожиданную блокировку кода.

Оценка набора select_for_update()запросов в режиме автоматической фиксации на поддерживаемых серверных ВМ является ошибкой, поскольку в этом случае строки не заблокированы. Если это разрешено, это будет способствовать повреждению данных и может быть легко вызвано вызовом кода, который ожидает запуска в транзакции вне транзакции.SELECT ... FOR UPDATETransactionManagementError

Использование select_for_update()на серверных ВМ, которые не поддерживают (например, SQLite), не будет иметь никакого эффекта. не будет добавлен в запрос, и ошибка не возникнет, если используется в режиме автофиксации.SELECT ... FOR UPDATESELECT ... FOR UPDATEselect_for_update()

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

Несмотря на то, как select_for_update()правило , не удается в режиме автоматической фиксации, так как TestCaseавтоматически оборачивает каждый тест в транзакции, вызывая select_for_update()в TestCaseдаже вне в atomic()блоке будет (возможно , неожиданно) пройти не поднимая TransactionManagementError. Для правильного тестирования select_for_update()вам следует использовать TransactionTestCase.

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

PostgreSQL не поддерживает select_for_update()с Windowвыражениями.

Изменено в Django 3.2:

no_keyАргумент был добавлен.

ofАргумент позволил на MySQL 8.0.1+.

raw()

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

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

Дополнительные сведения см. В разделе « Выполнение необработанных запросов SQL» .

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

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

Изменено в Django 3.2:

Значение paramsаргумента по умолчанию было изменено с Noneна пустой кортеж.

Операторы, возвращающие новый QuerySets

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

И ( &)

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

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

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

ИЛИ ( |)

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

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

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

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

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

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

get()

get( ** kwargs )

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

Entry.objects.get(id=1)
Entry.objects.get(blog=blog, entry_number=1)

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

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

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

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

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

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

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

from django.core.exceptions import ObjectDoesNotExist

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

create()

create( ** kwargs )

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

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

а также:

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

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

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

get_or_create()

get_or_create(по умолчанию = Нет , ** kwargs )

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

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

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

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's chapters, но оно выбирается только внутри контекста этой книги:

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

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

update_or_create()

update_or_create(по умолчанию = Нет , ** kwargs )

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

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

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.

bulk_create()

bulk_create( objs , batch_size = None , ignore_conflicts = False )

Этот метод эффективно вставляет предоставленный список объектов в базу данных (обычно только 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+). В других базах он не будет установлен.

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

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

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

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

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

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

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

Изменено в Django 3.1:

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

bulk_update()

bulk_update( объекты , поля , batch_size = Нет )

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

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

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

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

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

count()

count()

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

Пример:

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

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

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

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

in_bulk()

in_bulk( id_list = Нет , * , field_name = 'pk' )

Принимает список значений поля ( id_list) и field_nameдля этих значений и возвращает словарь, сопоставляющий каждое значение с экземпляром объекта с заданным значением поля. Если 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()пустой список, вы получите пустой словарь.

Изменено в Django 3.2:

Разрешено использование отдельного поля.

iterator()

iterator( chunk_size = 2000 )

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

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

Кроме того, использование iterator()аргументов приводит к тому, что предыдущие prefetch_related()вызовы игнорируются, поскольку эти две оптимизации не имеют смысла вместе.

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

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

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

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

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

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

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

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

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

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

Значение по умолчанию chunk_size2000 получено из расчета в списке рассылки psycopg :

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

latest()

latest( * поля )

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

Этот пример возвращает последнее значение 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.

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

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

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

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

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

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

Entry.objects.filter(pub_date__isnull=False).latest('pub_date')

earliest()

earliest( * поля )

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

first()

first()

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

Пример:

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

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

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

last()

last()

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

aggregate()

aggregate( * аргументы , ** kwargs )

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

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

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

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

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

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

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

Для более подробного обсуждения агрегирования см. Руководство по агрегированию .

exists()

exists()

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

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

Самый эффективный метод определения, является ли модель с уникальным полем (например primary_key) членом a QuerySet:

entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
    print("Entry contained in queryset")

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

if entry in some_queryset:
   print("Entry contained in QuerySet")

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

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

Что будет быстрее, чем:

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

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

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

update()

update( ** kwargs )

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

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

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

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

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

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

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

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

Однако фильтрация на основе связанных полей все еще возможна:

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

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

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

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

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

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

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

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

…сделай это:

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

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

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

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()
Упорядоченный набор запросов
Новое в Django 3.2.

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

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

Примечание

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

delete()

delete()

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

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

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

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

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

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

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

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

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

delete()Метод делает массовое удаление и не вызывает какие - либо delete() методов на вашу модели. Это, однако, излучать pre_deleteи post_deleteсигналы для всех удаленных объектов ( в том числе каскадных удалений).

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

ForeignKeys, настроенные так, чтобы не препятствовать быстрому пути удаления.on_delete DO_NOTHING

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

as_manager()

classmethodas_manager ()

Метод класса, который возвращает экземпляр Manager с копией QuerySetметодов. Дополнительные сведения см. В разделе « Создание менеджера с помощью методов QuerySet» .

explain()

explain( формат = Нет , ** параметры )

Возвращает строку 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запроса.

Изменено в Django 3.1:

'TREE'Добавлена поддержка формата MySQL 8.0.16+ и analyzeопция MariaDB и MySQL 8.0.18+.

Fieldпоиски

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

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

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

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

exact

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

Примеры:

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

Эквиваленты SQL:

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

MySQL сравнения

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

iexact

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

Пример:

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

Эквиваленты SQL:

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

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

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

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

contains

Тест на сдерживание с учетом регистра.

Пример:

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

Эквивалент SQL:

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

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

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

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

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для принудительного выполнения первого запроса. Без него вложенный запрос был бы выполнен, потому что QuerySets ленивы .

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действует как istartswithSQLite.

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 действует как iendswithSQLite. Обратитесь к документации примечания к базе данных для получения дополнительной информации.

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любом месте BETWEENSQL - для дат, чисел и даже символов.

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

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

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

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

date

Для полей datetime приводит значение как 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, поля datetime преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуются определения часовых поясов в базе данных .

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, поля datetime преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуются определения часовых поясов в базе данных .

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, поля datetime преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуются определения часовых поясов в базе данных .

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, поля datetime преобразуются в текущий часовой пояс перед фильтрацией. Для этого требуются определения часовых поясов в базе данных .

week

Для полей date и datetime верните номер недели (1-52 или 53) в соответствии с ISO-8601 , т. Е. Недели начинаются с понедельника, а первая неделя содержит первый четверг года.

Пример:

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

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

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

week_day

Для полей date и datetime совпадает "день недели". Позволяет связывать дополнительные поиски полей.

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

Пример:

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

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

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

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

iso_week_day

Новое в Django 3.1.

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

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

Пример:

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

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

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

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

quarter

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

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

Entry.objects.filter(pub_date__quarter=2)

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

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

time

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

Пример:

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

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

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

hour

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

Пример:

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

Эквивалент SQL:

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

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

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

minute

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

Пример:

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

Эквивалент SQL:

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

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

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

second

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

Пример:

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

Эквивалент SQL:

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

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

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

isnull

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

Пример:

Entry.objects.filter(pub_date__isnull=True)

Эквивалент SQL:

SELECT ... WHERE pub_date IS NULL;

Не рекомендуется, начиная с версии 3.1: Использование небулевых значений в правой части не рекомендуется, используйте вместо них True или False. В Django 4.0 возникнет исключение.

regex

Соответствие регулярному выражению с учетом регистра.

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

Пример:

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

Эквиваленты SQL:

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

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

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

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

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

iregex

Соответствие регулярному выражению без учета регистра.

Пример:

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

Эквиваленты SQL:

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

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

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

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

Функции агрегирования

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

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

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

Примечание

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

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

expressions

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

Изменено в Django 3.2:

Добавлена ​​поддержка преобразований поля.

output_field

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

Примечание

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

filter

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

См. Примеры использования условной агрегации и фильтрации аннотаций .

**extra

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

Avg

классAvg ( выражение , output_field = None , отличный = False , фильтр = None , ** за дополнительную плату )

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

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

Имеет один необязательный аргумент:

distinct

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

Count

classCount ( выражение , отличное = False , filter = None , ** extra )

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

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

Имеет один необязательный аргумент:

distinct

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

Max

classMax ( выражение , output_field = None , filter = None , ** extra )

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

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

Min

classMin ( выражение , output_field = None , filter = None , ** extra )

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

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

StdDev

classStdDev ( выражение , output_field = None , sample = False , filter = None , ** extra )

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

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

Имеет один необязательный аргумент:

sample

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

Sum

классSum ( выражение , output_field = None , отличный = False , фильтр = None , ** за дополнительную плату )

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

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

Имеет один необязательный аргумент:

distinct

Если distinct=True, Sumвозвращает сумму уникальных значений. Это SQL-эквивалент . Значение по умолчанию - .SUM(DISTINCT <field>)False

Variance

classVariance ( выражение , output_field = None , sample = False , filter = None , ** extra )

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

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

Имеет один необязательный аргумент:

sample

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

Copyright ©2021 All rights reserved