Справочник по API QuerySet
В данном документе описываются детали API QuerySet. Он опирается на материалы, представленные в руководствах по моделям и запросам к базе данных, поэтому перед чтением этого документа рекомендуется ознакомиться с ними.
В этом справочнике мы будем использовать примеры моделей веб-блога Примеры моделей веб-блога, представленные в руководстве по запросам к базе данных.
Когда QuerySet оцениваются
Внутренне, QuerySet можно создать, отфильтровать, ограничить с помощью срезов и в целом передавать без фактического обращения к базе данных. Действия с базой данных не выполняются до тех пор, пока вы не произведете оценку набора запросов.
Вы можете оценить QuerySet следующими способами:
-
Итерация.
QuerySetитерируемый, и он выполняет запрос к базе данных при первой итерации по нему. Например, это выведет заголовок всех записей в базе данных:for e in Entry.objects.all(): print(e.headline)Примечание: Не используйте этот метод, если вам нужно только определить, существует ли хотя бы один результат. Эффективнее использовать
exists(). -
Срезы. Как описано в Ограничение наборов запросов,
QuerySetможно ограничивать с помощью синтаксиса срезов Python. Ограничение невыполненногоQuerySetобычно возвращает другой невыполненныйQuerySet, но Django выполнит запрос к базе данных, если вы используете параметр «шаг» синтаксиса срезов, и вернёт список. Ограничение уже выполненногоQuerySetтакже возвращает список.Обратите также внимание, что, хотя срезы невыполненного
QuerySetвозвращают другой невыполненныйQuerySet, дальнейшие изменения (например, добавление дополнительных фильтров или изменение порядка) недопустимы, поскольку это не переводится в SQL и не имеет четкого смысла. - Сериализация/Кеширование. Подробности о том, что происходит при сериализации наборов запросов, смотрите в следующем разделе. Важно, что для целей этого раздела результаты считываются из базы данных.
-
repr().
QuerySetоценивается при вызовеrepr()на нём. Это сделано для удобства в интерактивном интерпретаторе Python, чтобы вы могли сразу увидеть результаты при взаимодействии с API. -
len().
QuerySetоценивается при вызовеlen()на нём. Как можно догадаться, это возвращает длину списка результатов.Примечание: Если вам нужно только определить количество записей в наборе (и не нужны сами объекты), гораздо эффективнее обработать подсчёт на уровне базы данных с помощью SQL-команды
SELECT COUNT(*). Django предоставляет методcount()именно для этой цели. -
list(). Выполнить оценку
QuerySet, вызвавlist()на нём. Например:entry_list = list(Entry.objects.all())
-
bool(). При использовании
QuerySetв контексте boolean, таком как операторы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().
Сериализация QuerySet
Если вы pickle 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. Тем не менее, безопасно (и полностью поддерживается) сериализовать и десериализовать содержимое атрибута, как описано здесь.
API QuerySet
Вот формальное объявление QuerySet:
-
class QuerySet(model=None, query=None, using=None)[source] -
Обычно вы будете взаимодействовать с
QuerySet, используя его с помощью цепочки фильтров. Для этого большинство методовQuerySetвозвращают новые наборы запросов. Эти методы подробно описаны ниже.Класс
QuerySetимеет два публичных атрибута, которые можно использовать для интроспекции:-
ordered -
True, еслиQuerySetупорядочен — т.е. имеет инструкциюorder_by()или порядок по умолчанию в модели.Falseв противном случае.
-
db -
База данных, которая будет использоваться, если этот запрос будет выполнен сейчас.
Примечание
Параметр
queryдляQuerySetсуществует, чтобы специализированные подклассы запросов, такие какGeoQuerySet, могли восстановить внутреннее состояние запроса. Значение параметра — непрозрачное представление этого состояния запроса и не является частью публичного API. Проще говоря: если вы не знаете, вам это не нужно. -
Методы, возвращающие новые QuerySet
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-01-03 И headline равно «Hello»:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
В SQL это соответствует:
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
В этом примере исключаются все записи, где pub_date позже 2005-01-03 ИЛИ заголовок равен «Hello»:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
В SQL это соответствует:
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
Обратите внимание на то, что второй пример более ограничен.
Если вам нужны более сложные запросы (например, запросы с OR операторами), вы можете использовать Q objects.
annotate()
-
annotate(*args, **kwargs)
Аннотирует каждый объект в QuerySet с предоставленным списком выражений запроса. Выражение может быть простым значением, ссылкой на поле в модели (или любой связанной модели) или агрегатным выражением (среднее значение, сумма и т. д.), вычисленным по объектам, связанным с объектами в QuerySet.
Каждый аргумент для annotate() — это аннотация, которая будет добавлена к каждому объекту в QuerySet, который возвращается.
Функции агрегирования, предоставляемые Django, описаны ниже в Функциях агрегирования.
Аннотации, заданные с помощью ключевых аргументов, будут использовать ключевое слово в качестве псевдонима аннотации. Анонимные аргументы будут иметь сгенерированный псевдоним на основе имени функции агрегирования и поля модели, которое агрегируется. Только агрегатные выражения, ссылающиеся на одно поле, могут быть анонимными аргументами. Все остальное должно быть ключевым аргументом.
Например, если вы работаете со списком блогов, вы можете захотеть определить, сколько записей было сделано в каждом блоге:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Модель Blog не определяет атрибут entry__count сама по себе, но с помощью ключевого аргумента для указания функции агрегирования вы можете управлять именем аннотации:
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
Для углубленного обсуждения агрегирования см. руководство по теме Агрегирование.
order_by()
-
order_by(*fields)
По умолчанию результаты, возвращаемые QuerySet, упорядочиваются по кортежу сортировки, заданному опцией ordering в Meta модели. Вы можете переопределить это на основе каждого QuerySet с помощью метода order_by.
Пример:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
Результат выше будет отсортирован по pub_date по убыванию, затем по headline по возрастанию. Минус перед "-pub_date" указывает на порядок по убыванию. Возрастающий порядок подразумевается. Для случайной сортировки используйте "?", как показано ниже:
Entry.objects.order_by('?')
Примечание: запросы order_by('?') могут быть дорогостоящими и медленными, в зависимости от используемого вами базы данных.
Чтобы отсортировать по полю в другой модели, используйте ту же синтаксическую конструкцию, что и при запросе через отношения моделей. То есть имя поля, за которым следует двойное подчеркивание (__), затем имя поля в новой модели, и так далее для всех моделей, которые вы хотите подключить. Например:
Entry.objects.order_by('blog__name', 'headline')
Если вы пытаетесь отсортировать по полю, которое является отношением к другой модели, Django будет использовать стандартную сортировку связанной модели или отсортирует по первичному ключу связанной модели, если не указано Meta.ordering. Например, поскольку модель Blog не имеет заданной стандартной сортировки:
Entry.objects.order_by('blog')
…это идентично:
Entry.objects.order_by('blog__id')
Если бы Blog имела ordering = ['name'], то первый набор запросов был бы идентичен:
Entry.objects.order_by('blog__name')
Вы также можете отсортировать по выражениям запроса, вызвав asc() или desc() для выражения:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
Будьте осторожны при сортировке по полям в связанных моделях, если вы также используете 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() обычно следует вызывать только на наборе запросов, у которого определена сортировка (например, при запросе к модели, которая определяет стандартную сортировку, или при использовании order_by()). Если такая сортировка не определена для данного QuerySet, вызов reverse() на нем не оказывает реального влияния (упорядочение было неопределенным до вызова reverse() и останется неопределенным после).
distinct()
-
distinct(*fields)
Возвращает новый набор запросов, который использует SELECT DISTINCT в своем запросе SQL. Это устраняет повторяющиеся строки из результатов запроса.
По умолчанию набор запросов не будет устранять повторяющиеся строки. На практике это редко проблема, потому что простые запросы, такие как Blog.objects.all(), не создают возможности получения повторяющихся строк результатов. Однако, если ваш запрос охватывает несколько таблиц, могут появиться повторяющиеся результаты при оценке QuerySet. Именно тогда используется distinct().
Примечание
Любые поля, используемые в вызове order_by(), включаются в столбцы SQL SELECT. Это иногда приводит к неожиданным результатам при совместном использовании с distinct(). Если вы отсортируете по полям из связанной модели, эти поля будут добавлены в выбранные столбцы, и они могут заставить строки, которые иначе были бы повторяющимися, выглядеть отличными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они существуют только для поддержки сортировки), иногда кажется, что возвращаются не-повторяющиеся результаты.
Аналогично, если вы используете запрос values() для ограничения выбранных столбцов, столбцы, используемые в любом вызове order_by() (или стандартная сортировка модели), по-прежнему будут участвовать и могут повлиять на уникальность результатов.
Мораль в том, что если вы используете distinct(), будьте осторожны с сортировкой по связанным моделям. Аналогично, при использовании distinct() и values() вместе, будьте осторожны при сортировке по полям, не включенным в вызов values().
Только в PostgreSQL вы можете передать позиционные аргументы (*fields), чтобы указать имена полей, к которым должно применяться DISTINCT. Это переводится в запрос SQL SELECT DISTINCT ON. Вот в чём разница. При обычном вызове distinct() база данных сравнивает каждое поле в каждой строке, чтобы определить, какие строки являются уникальными. При вызове distinct() с указанными именами полей база данных будет сравнивать только указанные имена полей.
Примечание
Когда вы указываете имена полей, вы обязательно должны предоставить order_by() в QuerySet, и поля в order_by() должны начинаться с полей в distinct() в том же порядке.
Например, SELECT DISTINCT ON (a) даёт вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите произвольную строку.
Примеры (те, которые следуют за первым, будут работать только в PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]
>>> Entry.objects.order_by('blog').distinct('blog')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]
>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]
Примечание
Помните, что order_by() использует любой установленный по умолчанию порядок сортировки связанной модели. Возможно, вам придётся явно отсортировать по связи _id или связанному полю, чтобы убедиться, что выражения DISTINCT ON соответствуют тем, что находятся в начале предложения ORDER BY. Например, если модель Blog определила ordering по name:
Entry.objects.order_by('blog').distinct('blog')
…это не сработает, потому что запрос будет отсортирован по blog__name, что не соответствует выражению DISTINCT ON. Вам нужно будет явно отсортировать по полю связи _id (blog_id в данном случае) или связанному полю (blog__pk), чтобы убедиться, что оба выражения соответствуют друг другу.
values()
-
values(*fields, **expressions)
Возвращает QuerySet, который возвращает словари, а не экземпляры моделей, при использовании в качестве итерируемого объекта.
Каждый из этих словарей представляет объект, где ключи соответствуют именам атрибутов объектов модели.
Этот пример сравнивает словари values() с обычными объектами модели:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Метод values() принимает необязательные позиционные аргументы, *fields, которые указывают имена полей, к которым должно быть ограничено SELECT. Если вы указываете поля, каждый словарь будет содержать только ключи/значения полей, которые вы указали. Если вы не указываете поля, каждый словарь будет содержать ключ и значение для каждого поля в таблице базы данных.
Пример:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Метод values() также принимает необязательные именованные аргументы, **expressions, которые передаются в annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
Агрегат внутри предложения values() применяется до других аргументов в том же предложении values(). Если вам нужно сгруппировать по другому значению, добавьте его в предыдущее предложение values().
>>> from django.db.models import Count
>>> Blog.objects.values('entry__authors', entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values('entry__authors').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
Несколько тонкостей, на которые стоит обратить внимание:
-
Если у вас есть поле, называющееся
foo, которое являетсяForeignKey, то вызовvalues()по умолчанию вернёт словарь с ключомfoo_id, так как это имя скрытого атрибута модели, который хранит фактическое значение (атрибутfooотносится к связанной модели). Когда вы вызываетеvalues()и передаёте имена полей, вы можете передать либоfoo, либоfoo_id, и вы получите то же самое (ключ словаря будет совпадать с именем поля, которое вы передали).Например:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values('blog') <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values('blog_id') <QuerySet [{'blog_id': 1}, ...]> - При использовании
values()вместе сdistinct(), имейте в виду, что сортировка может повлиять на результаты. Подробности см. в примечании кdistinct(). - Если вы используете предложение
values()после вызоваextra(), любые поля, определённые аргументомselectв вызовеextra(), должны быть явно включены в вызовvalues(). Любой вызовextra(), сделанный после вызоваvalues(), проигнорирует дополнительные выбранные поля. - Вызовы
only()иdefer()послеvalues()не имеют смысла, поэтому их выполнение вызовет ошибкуNotImplementedError.
Это полезно, когда вам нужно только значения из небольшого числа доступных полей и вам не нужна функциональность объекта модели. Эффективнее выбрать только необходимые поля.
Наконец, обратите внимание, что вы можете вызвать 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(), в этом случае будут возвращены все возможные комбинации.
Добавлена поддержка **expressions.
values_list()
-
values_list(*fields, flat=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 при наличии более одного поля — ошибка.
Если вы не передаёте никаких значений в 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,)]>
Добавлена поддержка выражений в *fields.
dates()
-
dates(field, kind, order='ASC')
Возвращает QuerySet, который вычисляется в список объектов datetime.date, представляющих все доступные даты определённого типа в содержании QuerySet.
field должно быть именем DateField вашей модели. kind должно быть либо "year", либо "month", либо "day". Каждый объект datetime.date в списке результатов «обрезается» до заданного type.
-
"year"возвращает список всех уникальных значений года для поля. -
"month"возвращает список всех уникальных значений года/месяца для поля. -
"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', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]
datetimes()
-
datetimes(field_name, kind, order='ASC', tzinfo=None)
Возвращает QuerySet, который вычисляется в список объектов datetime.datetime, представляющих все доступные даты определенного типа в содержании QuerySet.
field_name должен быть именем DateTimeField вашей модели.
kind должен быть либо "year", либо "month", либо "day", либо "hour", либо "minute", либо "second". Каждый объект datetime.datetime в списке результатов «обрезан» до заданного type.
order, по умолчанию равный 'ASC', должен быть либо 'ASC', либо 'DESC'. Это определяет порядок сортировки результатов.
tzinfo определяет часовой пояс, в который преобразуются даты и время до обрезки. Действительно, заданное значение даты и времени имеет разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo. Если это None, Django использует текущий часовой пояс. Он не оказывает никакого влияния, когда USE_TZ равен False.
Примечание
Эта функция выполняет преобразования часовых поясов непосредственно в базе данных. Вследствие этого ваша база данных должна быть способна интерпретировать значение tzinfo.tzname(None). Это переводится в следующие требования:
- SQLite: нет требований. Преобразования выполняются в Python с помощью pytz (установлен при установке Django).
- PostgreSQL: нет требований (см. Часовые пояса).
- Oracle: нет требований (см. Выбор файла часового пояса).
- MySQL: загрузить таблицы часовых поясов с помощью mysql_tzinfo_to_sql.
none()
-
none()
Вызов none() создаст запрос, который никогда не вернет какие-либо объекты, и никакой запрос не будет выполнен при доступе к результатам. Запрос qs.none() является экземпляром EmptyQuerySet.
Примеры:
>>> Entry.objects.none() <QuerySet []> >>> from django.db.models.query import EmptyQuerySet >>> isinstance(Entry.objects.none(), EmptyQuerySet) True
all()
-
all()
Возвращает копию текущего QuerySet (или подкласса QuerySet). Это может быть полезно в ситуациях, когда вы хотите передать либо менеджер модели, либо QuerySet и выполнить дополнительную фильтрацию по результату. После вызова all() для любого объекта, вы обязательно получите QuerySet для работы.
Когда QuerySet оценивается, он обычно кэширует свои результаты. Если данные в базе данных могли измениться с момента оценки QuerySet, вы можете получить обновленные результаты для того же запроса, вызвав all() для ранее оцененного QuerySet.
union()
-
union(*other_qs, all=False)
Использует оператор SQL UNION для объединения результатов двух или более QuerySet. Например:
>>> qs1.union(qs2, qs3)
Оператор UNION по умолчанию выбирает только уникальные значения. Чтобы разрешить дубликаты, используйте аргумент all=True.
union(), intersection() и difference() возвращают экземпляры модели типа первой QuerySet, даже если аргументы являются QuerySet других моделей. Передача разных моделей работает, если список SELECT одинаков во всех QuerySet (по крайней мере, типы, имена не важны, пока типы в одном и том же порядке). В таких случаях, вы должны использовать имена столбцов из первой QuerySet в методах QuerySet, примененных к результативному QuerySet. Например:
>>> qs1 = Author.objects.values_list('name')
>>> qs2 = Entry.objects.values_list('headline')
>>> qs1.union(qs2).order_by('name')
Кроме того, разрешены только LIMIT, OFFSET, COUNT(*), ORDER BY, а также указание столбцов (т. е. срезы, count(), order_by() и values()/values_list()) на результативном QuerySet. Кроме того, базы данных накладывают ограничения на то, какие операции разрешены в объединенных запросах. Например, большинство баз данных не разрешают LIMIT или OFFSET в объединенных запросах.
Была добавлена поддержка COUNT(*).
intersection()
-
intersection(*other_qs)
Использует оператор SQL INTERSECT для возвращения общих элементов двух или более QuerySet. Например:
>>> qs1.intersection(qs2, qs3)
См. union() для некоторых ограничений.
difference()
-
difference(*other_qs)
Использует оператор SQL EXCEPT, чтобы сохранить только элементы, присутствующие в QuerySet, но не в других QuerySet. Например:
>>> qs1.difference(qs2, qs3)
См. union() для некоторых ограничений.
select_related()
Возвращает QuerySet, который будет «следовать» за ссылками foreign key, выбирая дополнительные связанные данные при выполнении запроса. Это ускоряет производительность, что приводит к одному более сложному запросу, но означает, что последующее использование foreign key отношений не потребует запросов к базе данных.
Следующие примеры иллюстрируют разницу между обычными запросами и запросами с использованием select_related(). Вот обычный запрос:
# Hits the database. e = Entry.objects.get(id=5) # Hits the database again to get the related Blog object. b = e.blog
А вот запрос с использованием select_related:
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
Вы можете использовать select_related() с любым запросом объектов:
from django.utils import timezone
# Find all the blogs with entries scheduled to be published in the future.
blogs = set()
for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):
# Without select_related(), this would make a database query for each
# loop iteration in order to fetch the related blog for each entry.
blogs.add(e.blog)
Порядок цепочки filter() и select_related() не имеет значения. Эти запросы эквивалентны:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
Вы можете следовать за foreign keys аналогично запросам. Если у вас есть следующие модели:
from django.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(
City,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
class Book(models.Model):
# ...
author = models.ForeignKey(Person, on_delete=models.CASCADE)
… тогда вызов Book.objects.select_related('author__hometown').get(id=4) кэширует связанные Person и связанные City:
b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author # Doesn't hit the database.
c = p.hometown # Doesn't hit the database.
b = Book.objects.get(id=4) # No select_related() in this example.
p = b.author # Hits the database.
c = p.hometown # Hits the database.
Вы можете ссылаться на любые отношения ForeignKey или OneToOneField в списке полей, переданных в select_related().
Вы также можете ссылаться на обратное направление OneToOneField в списке полей, переданных в select_related — то есть вы можете пройти по OneToOneField обратно к объекту, на котором определено поле. Вместо указания имени поля используйте related_name для поля на связанном объекте.
Возможно, есть ситуации, когда вы хотите вызвать select_related() с большим количеством связанных объектов или когда вы не знаете все связи. В таких случаях можно вызвать select_related() без аргументов. Это позволит следовать всем не нулевым foreign keys, которые он сможет найти — необязательные foreign keys должны быть указаны. В большинстве случаев это не рекомендуется, так как, вероятно, это сделает базовый запрос более сложным и вернет больше данных, чем это необходимо.
Если вам нужно очистить список связанных полей, добавленных предыдущими вызовами select_related на QuerySet, вы можете передать None в качестве параметра:
>>> without_relations = queryset.select_related(None)
Цепочное вызов select_related работает аналогично другим методам — то есть, select_related('foo', 'bar') эквивалентно select_related('foo').select_related('bar').
prefetch_related()
Возвращает QuerySet, который автоматически извлечет связанные объекты для каждого из указанных запросов в одной группе.
Это имеет аналогичную цель select_related, в том, что оба предназначены для предотвращения потока запросов к базе данных, вызванного доступом к связанным объектам, но стратегия совершенно иная.
select_related работает, создавая SQL-соединение и включая поля связанного объекта в выражение SELECT. По этой причине, select_related получает связанные объекты в одном запросе к базе данных. Однако, чтобы избежать гораздо большего набора результатов, который бы получился при объединении по отношению «многие-ко-многим», select_related ограничен однозначными отношениями — внешним ключом и один-к-одному.
prefetch_related, с другой стороны, выполняет отдельный поиск для каждого отношения и выполняет «объединение» в Python. Это позволяет предварительно загружать объекты «многие-ко-многим» и «многие-к-одному», чего нельзя сделать с помощью select_related, в дополнение к отношениям внешнего ключа и один-к-одному, которые поддерживает select_related. Он также поддерживает предварительную загрузку GenericRelation и GenericForeignKey, однако, он должен быть ограничен однородным набором результатов. Например, предварительная загрузка объектов, на которые ссылается GenericForeignKey, поддерживается только если запрос ограничен одним ContentType.
Например, предположим, у вас есть следующие модели:
from django.db import models
class Topping(models.Model):
name = models.CharField(max_length=30)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
def __str__(self): # __unicode__ on Python 2
return "%s (%s)" % (
self.name,
", ".join(topping.name for topping in self.toppings.all()),
)
и вы выполняете:
>>> Pizza.objects.all() ["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
Проблема в том, что каждый раз, когда Pizza.__str__() запрашивает self.toppings.all(), ему необходимо обратиться к базе данных, поэтому Pizza.objects.all() будет выполнять запрос к таблице Toppings для каждого элемента в Pizze QuerySet.
Мы можем сократить до двух запросов, используя prefetch_related:
>>> Pizza.objects.all().prefetch_related('toppings')
Это подразумевает self.toppings.all() для каждого Pizza; теперь каждый раз, когда self.toppings.all() вызывается, вместо того, чтобы обращаться к базе данных за элементами, он найдет их в предварительно загруженном QuerySet кэше, который был заполнен в одном запросе.
То есть, все соответствующие дополнения были получены в одном запросе и использованы для создания QuerySets, которые имеют предварительно заполненный кэш соответствующих результатов; эти QuerySets затем используются в вызовах self.toppings.all().
Дополнительные запросы в prefetch_related() выполняются после того, как QuerySet начал оцениваться, и основной запрос был выполнен.
Если у вас есть итерируемый набор экземпляров модели, вы можете предварительно загрузить связанные атрибуты этих экземпляров, используя функцию prefetch_related_objects().
Обратите внимание, что кэш результатов основного запроса QuerySet и всех указанных связанных объектов будут полностью загружены в память. Это изменяет типичное поведение QuerySets, которое обычно старается избегать загрузки всех объектов в память до их необходимости, даже после выполнения запроса в базе данных.
Примечание
Помните, что, как всегда при использовании QuerySets, любые последующие связанные методы, подразумевающие другой запрос к базе данных, проигнорируют ранее кэшированные результаты и получат данные с помощью нового запроса к базе данных. Таким образом, если вы напишете следующее:
>>> pizzas = Pizza.objects.prefetch_related('toppings')
>>> [list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
…тот факт, что pizza.toppings.all() был предварительно загружен, вам не поможет. prefetch_related('toppings') предполагает pizza.toppings.all(), но pizza.toppings.filter() — это новый и другой запрос. Кэшированные результаты предварительной загрузки здесь не помогут; на самом деле это снижает производительность, так как вы выполнили запрос к базе данных, который вы не использовали. Поэтому используйте эту функцию с осторожностью!
Кроме того, если вы вызываете методы изменения базы данных add(), remove(), clear() или set(), на related managers, любой кэш предварительной загрузки для отношения будет очищен.
Была добавлена очистка кэша предварительной загрузки, описанная выше.
Вы также можете использовать стандартную синтаксис объединения для работы с связанными полями связанных полей. Предположим, что у нас есть дополнительная модель к приведенному выше примеру:
class Restaurant(models.Model):
pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
best_pizza = models.ForeignKey(Pizza, related_name='championed_by', on_delete=models.CASCADE)
Следующие варианты являются допустимыми:
>>> Restaurant.objects.prefetch_related('pizzas__toppings')
Это предварительно загрузит все пиццы, принадлежащие ресторанам, и все дополнения, принадлежащие этим пиццам. В результате будет выполнено всего 3 запроса к базе данных — один для ресторанов, один для пицц и один для дополнений.
>>> Restaurant.objects.prefetch_related('best_pizza__toppings')
Это получит лучшую пиццу и все дополнения к лучшей пицце для каждого ресторана. Это будет сделано в 3 запросах к базе данных — один для ресторанов, один для «лучших пицц» и один для дополнений.
Конечно, отношение best_pizza также можно получить, используя select_related, чтобы уменьшить количество запросов до 2:
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')
Поскольку предварительная загрузка выполняется после основного запроса (который включает соединения, необходимые для select_related), она может определить, что объекты best_pizza уже были получены, и пропустит их повторную загрузку.
Цепочки вызовов prefetch_related будут накапливать запросы, которые предварительно загружаются. Чтобы очистить любое поведение prefetch_related, передайте None в качестве параметра:
>>> non_prefetched = qs.prefetch_related(None)
Одно отличие при использовании prefetch_related состоит в том, что объекты, созданные запросом, могут быть общими между различными объектами, к которым они относятся, т.е. один экземпляр Python-модели может появиться более чем в одной точке дерева объектов, которые возвращаются. Это обычно происходит с отношениями внешнего ключа. Обычно это поведение не проблема и, на самом деле, экономит память и время ЦП.
Хотя prefetch_related поддерживает предварительную загрузку отношений GenericForeignKey, количество запросов будет зависеть от данных. Поскольку GenericForeignKey может ссылаться на данные в нескольких таблицах, для каждой ссылающейся таблицы требуется один запрос, а не один запрос для всех элементов. Могут быть дополнительные запросы к таблице ContentType, если соответствующие строки еще не были загружены.
prefetch_related в большинстве случаев будет реализован с помощью SQL-запроса, использующего оператор «IN». Это означает, что для большого QuerySet может быть сгенерирована большая фраза «IN», которая, в зависимости от базы данных, может иметь собственные проблемы с производительностью при разборе или выполнении SQL-запроса. Всегда профилируйте для вашего случая использования!
Обратите внимание, что если вы используете iterator() для запуска запроса, вызовы prefetch_related() будут игнорироваться, так как эти два оптимизации не имеют смысла вместе.
Вы можете использовать объект Prefetch для дальнейшего управления операцией предварительной загрузки.
В своей простейшей форме Prefetch эквивалентен традиционному поиску на основе строк:
>>> from django.db.models import Prefetch
>>> Restaurant.objects.prefetch_related(Prefetch('pizzas__toppings'))
Вы можете предоставить пользовательский набор результатов с необязательным аргументом queryset. Это можно использовать для изменения стандартного порядка сортировки набора результатов:
>>> Restaurant.objects.prefetch_related(
... Prefetch('pizzas__toppings', queryset=Toppings.objects.order_by('name')))
Или для вызова select_related(), где это применимо, чтобы еще больше сократить количество запросов:
>>> Pizza.objects.prefetch_related(
... Prefetch('restaurants', queryset=Restaurant.objects.select_related('best_pizza')))
Вы также можете назначить предварительно загруженный результат пользовательскому атрибуту с необязательным аргументом to_attr. Результат будет сохранен непосредственно в списке.
Это позволяет предварительно загружать одно и то же отношение несколько раз с разным QuerySet; например:
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
... Prefetch('pizzas', to_attr='menu'),
... Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'))
Поиски, созданные с помощью пользовательских to_attr, по-прежнему могут быть пройдены обычным способом другими поисками:
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
... Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'),
... 'vegetarian_menu__toppings')
Использование to_attr рекомендуется при фильтрации результатов предварительной загрузки, поскольку оно менее неоднозначно, чем хранение отфильтрованного результата в кэше связанного менеджера:
>>> queryset = Pizza.objects.filter(vegetarian=True)
>>>
>>> # Recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch('pizzas', queryset=queryset, to_attr='vegetarian_pizzas'))
>>> vegetarian_pizzas = restaurants[0].vegetarian_pizzas
>>>
>>> # Not recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
... Prefetch('pizzas', queryset=queryset))
>>> vegetarian_pizzas = restaurants[0].pizzas.all()
Пользовательская предварительная загрузка также работает с однозначными связанными отношениями, такими как прямой ForeignKey или OneToOneField. Обычно вы хотите использовать select_related() для этих отношений, но есть ряд случаев, когда предварительная загрузка с пользовательским QuerySet полезна:
- Вы хотите использовать
QuerySet, который выполняет дальнейшую предварительную загрузку связанных моделей. - Вы хотите предварительно загрузить только подмножество связанных объектов.
-
Вы хотите использовать методы оптимизации производительности, такие как
deferred fields:>>> queryset = Pizza.objects.only('name') >>> >>> restaurants = Restaurant.objects.prefetch_related( ... Prefetch('best_pizza', queryset=queryset))
Примечание
Порядок запросов имеет значение.
Рассмотрим следующие примеры:
>>> prefetch_related('pizzas__toppings', 'pizzas')
Это работает даже без порядка, потому что 'pizzas__toppings' уже содержит всю необходимую информацию, поэтому второй аргумент 'pizzas' фактически избыточен.
>>> prefetch_related('pizzas__toppings', Prefetch('pizzas', queryset=Pizza.objects.all()))
Это приведет к ошибке ValueError из-за попытки переопределить набор результатов ранее увиденного поиска. Обратите внимание, что неявный набор результатов был создан для обхода 'pizzas' в рамках поиска 'pizzas__toppings'.
>>> prefetch_related('pizza_list__toppings', Prefetch('pizzas', to_attr='pizza_list'))
Это вызовет ошибку AttributeError, так как 'pizza_list' еще не существует, когда 'pizza_list__toppings' обрабатывается.
Это соображение не ограничивается использованием объектов Prefetch. Некоторые продвинутые техники могут потребовать, чтобы запросы выполнялись в определенном порядке, чтобы избежать создания дополнительных запросов; поэтому рекомендуется всегда тщательно упорядочивать аргументы prefetch_related.
extra()
-
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
Иногда синтаксис запросов Django сам по себе не может легко выразить сложное WHERE условие. В таких особых случаях Django предоставляет модификатор extra() QuerySet — крючок для вставки специфических условий в SQL, генерируемый QuerySet.
Используйте этот метод в крайнем случае
Это старый API, который мы планируем в какой-то момент в будущем сделать устаревшим. Используйте его только в том случае, если вы не можете выразить свой запрос с помощью других методов набора запросов. Если вам необходимо его использовать, пожалуйста, отправьте запрос с использованием ключа QuerySet.extra с вашим случаем использования (сначала, пожалуйста, проверьте список существующих запросов), чтобы мы могли улучшить API набора запросов, чтобы позволить удалить 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) и нарушают принцип DRY, поэтому следует избегать их, если это возможно.
Укажите один или несколько из params, select, where или tables. Ни один из аргументов не является обязательным, но вы должны использовать хотя бы один из них.
-
selectАргумент
selectпозволяет поместить дополнительные поля вSELECT. Он должен быть словарем, сопоставляющим имена атрибутов с SQL-условиями, используемыми для расчета этого атрибута.Пример:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})В результате каждый
Entryобъект будет иметь дополнительный атрибут,is_recent, булево значение, представляющее, больше ли записьpub_date, чем 1 января 2006 года.Django вставляет заданный фрагмент SQL напрямую в
SELECTоператор, поэтому результирующий SQL приведенного выше примера будет чем-то вроде:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Следующий пример более сложный; он выполняет подзапрос, чтобы присвоить каждому результирующему
Blogобъекту атрибутentry_count, целое число, являющееся количеством связанныхEntryобъектов:Blog.objects.extra( select={ 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' }, )В этом конкретном случае мы используем тот факт, что запрос уже будет содержать таблицу
blog_blogв своемFROMусловии.Результирующий SQL приведенного выше примера будет:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Обратите внимание, что скобки, необходимые для большинства СУБД вокруг подзапросов, не требуются в
selectусловиях Django. Также обратите внимание, что некоторые серверные части баз данных, такие как некоторые версии MySQL, не поддерживают подзапросы.В некоторых редких случаях вам может потребоваться передать параметры в фрагменты SQL в
extra(select=...). Для этой цели используйте параметрselect_params. Посколькуselect_paramsявляется последовательностью, аselectатрибут — словарем, необходима осторожность, чтобы параметры правильно сопоставлялись с дополнительными элементами выбора. В этой ситуации вы должны использоватьcollections.OrderedDictдля значенияselect, а не обычный словарь Python.Это сработает, например:
Blog.objects.extra( select=OrderedDict([('a', '%s'), ('b', '%s')]), select_params=('one', 'two'))Если вам нужно использовать литерал
%sвнутри вашей строки выбора, используйте последовательность%%s. -
where/tablesВы можете определить явные SQL
WHEREусловия — возможно, для выполнения неявных соединений — с помощью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, второй и последующие появления должны использовать псевдонимы, чтобы база данных могла их различать. Если вы ссылаетесь на дополнительную таблицу, добавленную в параметр extrawhere, это приведёт к ошибкам.Обычно вы добавляете только дополнительные таблицы, которые не появляются в запросе. Однако, если указанный выше случай произойдёт, есть несколько решений. Во-первых, посмотрите, можете ли вы обойтись без включения дополнительной таблицы и использовать ту, что уже есть в запросе. Если это невозможно, поместите ваш вызов
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, в начале набора результатов (Trueсортируется передFalseв порядке убывания).Кстати, это демонстрирует, что вы можете совершать несколько вызовов
extra(), и он будет работать так, как вы ожидаете (добавляя новые ограничения каждый раз). -
paramsПараметр
where, описанный выше, может использовать стандартные плейсхолдеры строк Python для баз данных —'%s'для указания параметров, которые движок базы данных должен автоматически заключить в кавычки. Аргументparams— это список дополнительных параметров для подстановки.Пример:
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Всегда используйте
paramsвместо встраивания значений напрямую вwhere, потому чтоparamsобеспечит правильное цитирование значений в соответствии с вашей конкретной частью сервера. Например, кавычки будут корректно экранированы.Плохо:
Entry.objects.extra(where=["headline='Lennon'"])
Хорошо:
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Предупреждение
Если вы выполняете запросы к MySQL, обратите внимание, что неявное приведение типов MySQL может привести к неожиданным результатам при смешивании типов. Если вы запрашиваете столбец типа строка, но с целочисленным значением, MySQL приведёт типы всех значений в таблице к целочисленному типу перед выполнением сравнения. Например, если ваша таблица содержит значения 'abc', 'def' и вы запрашиваете WHERE mycolumn=0, обе строки будут соответствовать. Чтобы предотвратить это, выполните правильное приведение типов перед использованием значения в запросе.
defer()
-
defer(*fields)
В некоторых сложных ситуациях моделирования данных ваши модели могут содержать много полей, некоторые из которых могут содержать много данных (например, текстовые поля) или требовать дорогостоящей обработки для преобразования в объекты Python. Если вы используете результаты набора запросов в какой-либо ситуации, где вы не знаете, нужны ли вам эти конкретные поля, когда вы изначально получаете данные, вы можете указать Django, чтобы он не извлекал их из базы данных.
Это делается путем передачи имен полей, которые не нужно загружать, в defer():
Entry.objects.defer("headline", "body")
Набор запросов, который имеет отложенные поля, по-прежнему вернёт экземпляры моделей. Каждое отложенное поле будет извлечено из базы данных, если вы обратитесь к этому полю (по одному за раз, а не ко всем отложенным полям сразу).
Вы можете совершать несколько вызовов defer(). Каждый вызов добавляет новые поля в отложенный набор:
# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")
Порядок добавления полей в отложенный набор не имеет значения. Вызов defer() с именем поля, которое уже отложено, не вреден (поле по-прежнему будет отложено).
Вы можете отложить загрузку полей в связанных моделях (если связанные модели загружаются с помощью select_related()) с использованием стандартной двойной записи для разделения связанных полей:
Blog.objects.select_related().defer("entry__headline", "entry__body")
Если вы хотите очистить набор отложенных полей, передайте None в качестве параметра в defer():
# Load all fields immediately. my_queryset.defer(None)
Некоторые поля в модели не будут отложены, даже если вы их запросите. Вы никогда не можете отложить загрузку первичного ключа. Если вы используете select_related() для извлечения связанных моделей, вы не должны откладывать загрузку поля, которое связывает первичную модель со связанной, так как это приведёт к ошибке.
Примечание
Метод defer() (и его аналог, only(), ниже) предназначен только для сложных случаев. Они обеспечивают оптимизацию, когда вы тщательно проанализировали свои запросы и понимаете точно, какая информация вам нужна, и измерили, что разница между возвращением необходимых полей и полным набором полей модели будет значительной.
Даже если вы считаете, что находитесь в ситуации с продвинутым использованием, используйте defer() только в том случае, если во время загрузки набора запросов нельзя определить, понадобятся ли вам дополнительные поля или нет. Если вы часто загружаете и используете определенный подмножество ваших данных, лучшим выбором является нормализация ваших моделей и размещение не загруженных данных в отдельной модели (и таблице базы данных). Если столбцы обязательно должны остаться в одной таблице по какой-то причине, создайте модель с Meta.managed = False (см. managed attribute документацию), содержащую только поля, которые вам обычно нужно загружать и использовать, где вы могли бы в противном случае вызвать defer(). Это делает ваш код более понятным для читателя, немного быстрее и потребляет немного меньше памяти в процессе Python.
Например, обе эти модели используют одну и ту же базу данных:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = 'app_largetable'
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = 'app_largetable'
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.all().defer('f2')
Если в необработанной модели требуется дублировать много полей, может быть лучше создать абстрактную модель с общими полями, а затем сделать так, чтобы необработанные и обработанные модели наследовали от абстрактной модели.
Примечание
При вызове save() для экземпляров с отложенными полями сохраняются только загруженные поля. Дополнительные сведения см. в save().
only()
-
only(*fields)
Метод only() по существу является обратным defer(). Вы вызываете его с полями, которые не должны откладываться при получении модели. Если у вас есть модель, где почти все поля нужно отложить, использование only() для указания дополнительного набора полей может привести к более простому коду.
Предположим, у вас есть модель с полями name, age и biography. Два следующих набора запросов одинаковы с точки зрения отложенных полей:
Person.objects.defer("age", "biography")
Person.objects.only("name")
Всякий раз, когда вы вызываете only(), это заменяет набор полей, которые нужно загрузить немедленно. Название метода запоминающееся: только эти поля загружаются немедленно; остальные откладываются. Таким образом, последовательные вызовы only() приводят к тому, что только последние поля учитываются:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
Поскольку defer() действует поэтапно (добавляя поля в список отложенных), вы можете объединить вызовы only() и defer(), и вещи будут вести себя логично:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline 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(alias)
Этот метод используется для управления базой данных, к которой будет применяться QuerySet, если вы используете более одной базы данных. Единственный аргумент этого метода — псевдоним базы данных, как определено в DATABASES.
Например:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
select_for_update()
-
select_for_update(nowait=False, skip_locked=False)
Возвращает набор запросов, который заблокирует строки до конца транзакции, создавая оператор SQL SELECT ... FOR UPDATE на поддерживаемых базах данных.
Например:
entries = Entry.objects.select_for_update().filter(author=request.user)
Все сопоставленные записи будут заблокированы до конца блока транзакции, что означает, что другие транзакции не смогут изменить или получить блокировки на них.
Обычно, если другая транзакция уже получила блокировку на одной из выбранных строк, запрос будет блокироваться, пока блокировка не будет освобождена. Если это не то поведение, которое вы хотите, вызовите select_for_update(nowait=True). Это сделает вызов неблокирующим. Если другая транзакция уже получила конфликтующую блокировку, при оценке набора запросов будет поднято исключение DatabaseError. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True) вместо этого. nowait и skip_locked являются взаимоисключающими, и попытка вызвать select_for_update() с обоими включенными параметрами приведет к ValueError.
В настоящее время postgresql, oracle и mysql базы данных поддерживают select_for_update(). Однако MySQL не поддерживает аргументы nowait и skip_locked.
Передача nowait=True или skip_locked=True в select_for_update() с помощью баз данных, которые не поддерживают эти параметры, таких как MySQL, приведет к исключению DatabaseError. Это предотвращает неожиданное блокирование кода.
Оценивание набора запросов с select_for_update() в режиме автоподтверждения на бэкендах, которые поддерживают SELECT ... FOR UPDATE, является ошибкой TransactionManagementError, потому что строки в этом случае не блокируются. Если это было разрешено, это облегчило бы повреждение данных и могло быть легко вызвано кодом, который ожидает выполнения вне транзакции.
Использование select_for_update() на бэкендах, которые не поддерживают SELECT ... FOR UPDATE (например, SQLite), не повлияет. SELECT ... FOR UPDATE не будет добавлен в запрос, и ошибка не возникнет, если select_for_update() используется в режиме автоподтверждения.
Предупреждение
Хотя select_for_update() обычно терпит неудачу в режиме автоподтверждения, поскольку TestCase автоматически оборачивает каждый тест в транзакцию, вызов select_for_update() в TestCase даже вне блока atomic() пройдёт (возможно, неожиданно) без возникновения TransactionManagementError. Для правильного тестирования select_for_update() вы должны использовать TransactionTestCase.
Добавлен аргумент skip_locked.
raw()
-
raw(raw_query, params=None, translations=None)
Принимает необработанный запрос SQL, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet. Этот экземпляр RawQuerySet можно перебирать, как обычный набор QuerySet, чтобы получить экземпляры объектов.
Дополнительную информацию см. в разделе Выполнение необработанных запросов SQL.
Предупреждение
raw() всегда запускает новый запрос и не учитывает предыдущую фильтрацию. Поэтому его следует вызывать, как правило, из Manager или из нового экземпляра QuerySet.
Методы, которые не возвращают наборы запросов
Следующие методы QuerySet обрабатывают QuerySet и возвращают что-то кроме набора запросов.
Эти методы не используют кэш (см. Кэширование и наборы запросов). Вместо этого они запрашивают базу данных каждый раз, когда их вызывают.
get()
-
get(**kwargs)
Возвращает объект, соответствующий заданным параметрам поиска, которые должны быть в формате, описанном в Поиск по полям.
get() вызывает MultipleObjectsReturned, если найдено более одного объекта. Исключение MultipleObjectsReturned является атрибутом класса модели.
get() вызывает исключение DoesNotExist, если для заданных параметров объект не был найден. Это исключение является атрибутом класса модели. Пример:
Entry.objects.get(id='foo') # raises Entry.DoesNotExist
Исключение DoesNotExist наследуется от django.core.exceptions.ObjectDoesNotExist, поэтому вы можете обработать несколько исключений DoesNotExist. Пример:
from django.core.exceptions import ObjectDoesNotExist
try:
e = Entry.objects.get(id=3)
b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
print("Either the entry or blog doesn't exist.")
Если ожидается, что набор запросов вернёт одну строку, вы можете использовать get() без аргументов для возвращения объекта этой строки:
entry = Entry.objects.filter(...).exclude(...).get()
create()
-
create(**kwargs)
Удобный метод для создания объекта и его сохранения в одном шаге. Таким образом:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
и:
p = Person(first_name="Bruce", last_name="Springsteen") p.save(force_insert=True)
эквивалентны.
Параметр force_insert документирован в другом месте, но он означает, что новый объект всегда будет создан. Обычно об этом не нужно беспокоиться. Однако, если ваша модель содержит значение первичного ключа, заданное вручную, и если это значение уже существует в базе данных, вызов create() завершится ошибкой IntegrityError, так как первичные ключи должны быть уникальными. Будьте готовы обработать исключение, если вы используете значения первичных ключей, задаваемые вручную.
get_or_create()
-
get_or_create(defaults=None, **kwargs)
Удобный метод для поиска объекта с заданными kwargs (может быть пустым, если ваша модель имеет значения по умолчанию для всех полей), создавая его при необходимости.
Возвращает кортеж из (object, created), где object — полученный или созданный объект, а created — логическое значение, указывающее, был ли создан новый объект.
Это предназначено в качестве сокращения для шаблонного кода. Например:
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
Этот шаблон становится довольно громоздким по мере увеличения количества полей в модели. Вышеприведенный пример можно переписать, используя 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. Если найдено несколько объектов, 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, и вы хотите использовать его как точное соответствие в get_or_create(), просто используйте 'defaults__exact', как показано ниже:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
Метод get_or_create() имеет аналогичное поведение при ошибках методу create(), когда вы используете вручную заданные первичные ключи. Если нужно создать объект, а ключ уже существует в базе данных, будет выброшено исключение IntegrityError.
Этот метод является атомарным при условии корректного использования, правильной конфигурации базы данных и правильного поведения подлежащей базы данных. Однако, если уникальность не проверяется на уровне базы данных для kwargs, используемого в вызове get_or_create (см. unique или unique_together), этот метод подвержен гонке, что может привести к одновременной вставке нескольких строк с одинаковыми параметрами.
Если вы используете MySQL, обязательно используйте уровень изоляции READ COMMITTED, а не REPEATABLE READ (по умолчанию), иначе могут возникнуть случаи, когда get_or_create вызовет IntegrityError, но объект не появится в последующем вызове get().
Наконец, о применении get_or_create() в представлениях Django. Пожалуйста, используйте его только в POST запросах, если у вас нет веских причин не делать этого. GET запросы не должны оказывать никакого влияния на данные. Вместо этого используйте POST всякий раз, когда запрос на страницу оказывает побочный эффект на ваши данные. Дополнительную информацию см. в Безопасные методы в спецификации HTTP.
Предупреждение
Вы можете использовать get_or_create() через атрибуты ManyToManyField и обратные связи. В этом случае вы ограничите запросы в рамках этой связи. Это может привести к проблемам целостности, если вы не используете его последовательно.
Пусть будут следующие модели:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
Вы можете использовать get_or_create() через поле главы книги, но оно извлекает только в рамках этой книги:
>>> book = Book.objects.create(title="Ulysses") >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, True) >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, False) >>> Chapter.objects.create(title="Chapter 1") <Chapter: Chapter 1> >>> book.chapters.get_or_create(title="Chapter 1") # Raises IntegrityError
Это происходит потому, что он пытается получить или создать «Главу 1» через книгу «Улисс», но не может сделать ни того, ни другого: связь не может получить эту главу, потому что она не связана с этой книгой, но и не может её создать, потому что поле title должно быть уникальным.
Добавлена поддержка вызываемых значений в defaults.
update_or_create()
-
update_or_create(defaults=None, **kwargs)
Удобный метод для обновления объекта с заданными kwargs, создавая новый, если необходимо. defaults — это словарь пар (поле, значение), используемый для обновления объекта. Значения в defaults могут быть вызываемыми.
Возвращает кортеж из (object, created), где object — созданный или обновлённый объект, а created — логическое значение, указывающее, был ли создан новый объект.
Метод update_or_create пытается извлечь объект из базы данных на основе заданных kwargs. Если совпадение найдено, он обновляет поля, переданные в словаре defaults.
Это предназначено в качестве сокращения для шаблонного кода. Например:
defaults = {'first_name': 'Bob'}
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {'first_name': 'John', 'last_name': 'Lennon'}
new_values.update(defaults)
obj = Person(**new_values)
obj.save()
Этот шаблон становится довольно громоздким по мере увеличения количества полей в модели. Вышеприведенный пример можно переписать, используя update_or_create() следующим образом:
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
Для подробного описания того, как имена, переданные в kwargs, решаются, см. get_or_create().
Как описано выше в get_or_create(), этот метод подвержен гонке, что может привести к одновременной вставке нескольких строк, если уникальность не проверяется на уровне базы данных.
Добавлена поддержка вызываемых значений в defaults.
bulk_create()
-
bulk_create(objs, batch_size=None)
Этот метод вставляет предоставленный список объектов в базу данных эффективным способом (обычно только 1 запрос, независимо от количества объектов):
>>> Entry.objects.bulk_create([ ... Entry(headline='This is a test'), ... Entry(headline='This is only a test'), ... ])
Однако это имеет ряд ограничений:
- Метод
save()модели не будет вызван, и сигналыpre_saveиpost_saveне будут отправлены. - Он не работает с дочерними моделями в сценарии наследования с несколькими таблицами.
- Если первичный ключ модели является
AutoField, он не извлекает и не устанавливает атрибут первичного ключа, какsave(), за исключением случаев, когда поддерживает это базовый механизм БД (в настоящее время PostgreSQL). - Он не работает с отношениями «многие ко многим».
Была добавлена поддержка установки первичных ключей для объектов, созданных с помощью bulk_create(), при использовании PostgreSQL.
Параметр batch_size управляет количеством объектов, создаваемых в одном запросе. По умолчанию все объекты создаются в одной партии, за исключением SQLite, где по умолчанию используется не более 999 переменных на запрос.
count()
-
count()
Возвращает целое число, представляющее количество объектов в базе данных, соответствующих QuerySet. Метод count() никогда не вызывает исключений.
Пример:
# Returns the total number of entries in the database. Entry.objects.count() # Returns the number of entries whose headline contains 'Lennon' Entry.objects.filter(headline__contains='Lennon').count()
Вызов count() выполняет SELECT COUNT(*) за кулисами, поэтому вы всегда должны использовать count(), а не загружать все записи в объекты Python и вызывать len() на результате (если вам не нужно загружать объекты в память, в этом случае len() будет быстрее).
В зависимости от используемой базы данных (например, PostgreSQL или MySQL), count() может вернуть большое целое число вместо обычного целого числа Python. Это особенность реализации, которая не должна создавать реальных проблем.
Обратите внимание, что если вам нужно количество элементов в QuerySet и вы также извлекаете экземпляры моделей из него (например, итерируясь по нему), то, вероятно, эффективнее использовать len(queryset), который не вызовет дополнительный запрос к базе данных, как count().
in_bulk()
-
in_bulk(id_list=None)
Принимает список значений первичных ключей и возвращает словарь, сопоставляющий каждое значение первичного ключа экземпляру объекта с заданным идентификатором. Если список не указан, возвращаются все объекты в наборе запросов.
Пример:
>>> 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>}
Если вы передадите in_bulk() пустой список, вы получите пустой словарь.
В более старых версиях id_list был обязательным аргументом.
iterator()
-
iterator()
Вычисляет QuerySet (выполняя запрос) и возвращает итератор (см. PEP 234) по результатам. Набор запросов обычно кэширует свои результаты внутри себя, чтобы повторные оценки не приводили к дополнительным запросам. В отличие от этого, iterator() будет читать результаты непосредственно, не производя никакого кэширования на уровне QuerySet (внутренне, по умолчанию итератор вызывает iterator() и кэширует возвращаемое значение). Для набора запросов, который возвращает большое количество объектов, которые вам нужно обработать только один раз, это может привести к лучшей производительности и значительному сокращению потребления памяти.
Обратите внимание, что использование iterator() на наборе запросов, который уже был вычислен, заставит его перевычислиться, повторив запрос.
Кроме того, использование iterator() игнорирует предыдущие вызовы prefetch_related(), так как эти два оптимизация не имеют смысла вместе.
В зависимости от бэкенда базы данных, результаты запроса будут загружены сразу или получены из базы данных потоком с помощью курсоров на стороне сервера.
С курсорами на стороне сервера
Oracle и PostgreSQL используют курсоры на стороне сервера для потоковой передачи результатов из базы данных, не загружая весь набор результатов в память.
Драйвер Oracle базы данных всегда использует курсоры на стороне сервера.
В PostgreSQL курсоры на стороне сервера будут использоваться только тогда, когда значение параметра DISABLE_SERVER_SIDE_CURSORS установлено в значение False. Прочитайте Пулы транзакций и курсоры на стороне сервера, если вы используете пул подключений, настроенный в режиме пула транзакций. Если курсоры на стороне сервера отключены, поведение такое же, как у баз данных, которые не поддерживают курсоры на стороне сервера.
Без курсоров на стороне сервера
MySQL и SQLite не поддерживают потоковую передачу результатов, поэтому драйверы баз данных Python загружают весь набор результатов в память. Затем набор результатов преобразуется в объекты строк Python адаптером базы данных с использованием метода fetchmany(), определенного в PEP 249.
Была добавлена поддержка курсоров на стороне сервера для PostgreSQL.
latest()
-
latest(field_name=None)
Возвращает последний объект в таблице по дате, используя предоставленное поле даты.
Этот пример возвращает последний Entry в таблице в соответствии с полем pub_date:
Entry.objects.latest('pub_date')
Если в Meta вашей модели указано get_latest_by, вы можете опустить аргумент field_name для earliest() или latest(). Django по умолчанию будет использовать поле, указанное в get_latest_by.
Как и get(), earliest() и latest() вызывают исключение DoesNotExist, если объект с заданными параметрами отсутствует.
Обратите внимание, что earliest() и latest() существуют исключительно для удобства и читабельности.
earliest() и latest() могут возвращать экземпляры с датами NULL.
Поскольку сортировка делегируется базе данных, результаты по полям, допускающим значения NULL, могут сортироваться по-разному, если вы используете разные базы данных. Например, PostgreSQL и MySQL сортируют значения NULL так, как будто они больше, чем ненулевые значения, в то время как SQLite делает наоборот.
Возможно, вам захочется отфильтровать нулевые значения:
Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
earliest()
-
earliest(field_name=None)
В остальном работает аналогично latest(), за исключением изменения направления.
first()
-
first()
Возвращает первый объект, соответствующий набору запросов, или None, если соответствующего объекта нет. Если у набора запросов нет определенной сортировки, набор запросов автоматически сортируется по первичному ключу.
Пример:
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(*args, **kwargs)
Возвращает словарь агрегированных значений (средних значений, сумм и т. д.), рассчитанных по QuerySet. Каждый аргумент aggregate() указывает значение, которое будет включено в возвращаемый словарь.
Функции агрегации, предоставляемые Django, описаны в Функциях агрегирования ниже. Поскольку агрегаты также являются выражениями запроса, вы можете объединять агрегаты с другими агрегатами или значениями для создания сложных агрегатов.
Агрегаты, указанные с помощью ключевых аргументов, будут использовать ключевое слово в качестве имени аннотации. Анонимные аргументы будут иметь имя, сгенерированное на основе имени функции агрегирования и поля модели, которое агрегируется. Сложные агрегаты не могут использовать анонимные аргументы и должны указывать ключевой аргумент в качестве псевдонима.
Например, при работе со записями блога вы можете узнать количество авторов, которые внесли вклад в записи блога:
>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
Используя ключевой аргумент для указания функции агрегации, вы можете контролировать имя агрегированного значения, которое возвращается:
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}
Для углубленного обсуждения агрегирования см. руководство по теме агрегирования.
exists()
-
exists()
Возвращает True, если QuerySet содержит какие-либо результаты, и False в противном случае. Это пытается выполнить запрос наиболее простым и быстрым способом, но оно выполняет почти такой же запрос, как обычный запрос QuerySet.
exists() полезно для поиска, связанного с членством объекта в QuerySet и для проверки существования любых объектов в QuerySet, особенно в контексте большого QuerySet.
Наиболее эффективный способ определить, является ли модель с уникальным полем (например, primary_key) членом QuerySet, таков:
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
print("Entry contained in queryset")
Что будет быстрее, чем следующее, требующее оценки и итерации по всему набору запросов:
if entry in some_queryset:
print("Entry contained in QuerySet")
И чтобы проверить, содержит ли набор запросов какие-либо элементы:
if some_queryset.exists():
print("There is at least one object in some_queryset")
Что будет быстрее, чем:
if some_queryset:
print("There is at least one object in some_queryset")
… но не на большую величину (поэтому для получения выгоды от эффективности нужен большой набор запросов).
Кроме того, если some_queryset еще не был оценен, но вы знаете, что он будет оценен в какой-то момент, то использование some_queryset.exists() потребует больше работы в целом (один запрос для проверки существования плюс дополнительный для последующего получения результатов), чем просто использование bool(some_queryset), которое извлекает результаты и затем проверяет, были ли возвращены какие-либо результаты.
update()
-
update(**kwargs)
Выполняет запрос SQL обновления для указанных полей и возвращает количество строк, соответствующих условиям (которое может не совпадать с количеством обновленных строк, если некоторые строки уже имеют новое значение).
Например, чтобы отключить комментарии для всех записей блога, опубликованных в 2010 году, можно сделать следующее:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(Предполагается, что ваша модель Entry имеет поля pub_date и comments_on.)
Вы можете обновлять несколько полей — ограничений по количеству нет. Например, здесь мы обновляем поля comments_on и headline:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
Метод update() применяется мгновенно, и единственное ограничение для обновляемого QuerySet заключается в том, что он может обновлять только столбцы в основной таблице модели, а не в связанных моделях. Например, вы не можете сделать это:
>>> Entry.objects.update(blog__name='foo') # Won't work!
Однако фильтрация по связанным полям всё ещё возможна:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
Вы не можете вызвать update() для QuerySet, для которого был взят срез или который по другим причинам больше не может быть отфильтрован.
Метод update() возвращает количество затронутых строк:
>>> Entry.objects.filter(id=64).update(comments_on=True) 1 >>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True) 0 >>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False) 132
Если вам нужно обновить запись и вам не нужно ничего делать с объектом модели, самый эффективный способ — вызвать update(), а не загружать объект модели в память. Например, вместо этого:
e = Entry.objects.get(id=10) e.comments_on = False e.save()
… сделайте так:
Entry.objects.filter(id=10).update(comments_on=False)
Использование update() также предотвращает гонку, в которой что-то может измениться в вашей базе данных в короткий промежуток времени между загрузкой объекта и вызовом save().
Наконец, понимайте, что update() выполняет обновление на уровне SQL и, следовательно, не вызывает никаких save() методов для ваших моделей, а также не генерирует сигналы pre_save или post_save (которые являются следствием вызова Model.save()). Если вы хотите обновить множество записей для модели с настраиваемым методом save(), перебирайте их и вызывайте save(), как показано здесь:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
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})
По умолчанию ForeignKey Django эмулирует ограничение SQL ON DELETE CASCADE — другими словами, любые объекты с внешними ключами, указывающими на объекты, которые будут удалены, будут удалены вместе с ними. Например:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'weblog.Blog': 1, 'weblog.Entry': 2, 'weblog.Entry_authors': 2})
Это поведение каскадного удаления можно настроить с помощью аргумента on_delete для ForeignKey.
Метод delete() выполняет массовое удаление и не вызывает никаких delete() методов для ваших моделей. Однако он генерирует сигналы pre_delete и post_delete для всех удалённых объектов (включая каскадные удаления).
Django необходимо извлечь объекты в память, чтобы отправить сигналы и обработать каскады. Однако, если нет каскадов и сигналов, Django может использовать быстрый путь и удалять объекты без извлечения в память. Для больших удалений это может привести к значительному снижению использования памяти. Количество выполняемых запросов тоже может быть уменьшено.
Внешние ключи, установленные в on_delete DO_NOTHING, не препятствуют использованию быстрого пути при удалении.
Обратите внимание, что запросы, сгенерированные при удалении объекта, являются деталями реализации и могут быть изменены.
as_manager()
-
classmethod as_manager()
Метод класса, возвращающий экземпляр Manager с копией методов QuerySet. Подробнее см. Создание менеджера с методами QuerySet.
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-бекенда и Unicode (не ASCII) строк учтите примечание к базе данных о сравнении строк. SQLite не выполняет нечувствительное к регистру сопоставление для Unicode-строк.
contains
Чувствительное к регистру проверка на вхождение.
Пример:
Entry.objects.get(headline__contains='Lennon')
Эквивалент SQL:
SELECT ... WHERE headline LIKE '%Lennon%';
Обратите внимание, что это будет соответствовать заголовку 'Lennon honored today', но не 'lennon
honored today'.
Пользователи SQLite
SQLite не поддерживает операторы сопоставления строк, чувствительные к регистру; оператор LIKE ведет себя как оператор icontains для SQLite. Для получения дополнительной информации см. примечание к базе данных.
icontains
Проверка на нечувствительное к регистру вхождение.
Пример:
Entry.objects.get(headline__icontains='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline ILIKE '%Lennon%';
Пользователи SQLite
При использовании SQLite-бэкэнда и Unicode-строк (не ASCII) учитывайте примечание к базе данных о сравнении строк.
in
В заданном списке.
Пример:
Entry.objects.filter(id__in=[1, 3, 4])
Эквивалент в SQL:
SELECT ... WHERE id IN (1, 3, 4);
Вы также можете использовать запрос QuerySet для динамической оценки списка значений вместо предоставления списка литеральных значений:
inner_qs = Blog.objects.filter(name__contains='Cheddar') entries = Entry.objects.filter(blog__in=inner_qs)
Этот QuerySet будет вычисляться как подзапрос:
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() вызов вокруг запроса к таблице Blog 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 ведет себя как istartswith для SQLite.
istartswith
Нечувствительное к регистру начало с.
Пример:
Entry.objects.filter(headline__istartswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline ILIKE 'Lennon%';
Пользователи SQLite
При использовании SQLite-бэкэнда и Unicode-строк (не ASCII) учитывайте примечание к базе данных о сравнении строк.
endswith
Чувствительное к регистру окончание с.
Пример:
Entry.objects.filter(headline__endswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline LIKE '%Lennon';
Пользователи SQLite
SQLite не поддерживает операторы сопоставления строк, чувствительные к регистру LIKE; endswith ведет себя как iendswith для SQLite. Для получения дополнительной информации см. документацию примечания к базе данных.
iendswith
Нечувствительное к регистру окончание с.
Пример:
Entry.objects.filter(headline__iendswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline ILIKE '%Lennon'
Пользователи SQLite
При использовании SQLite-бэкэнда и Unicode-строк (не ASCII) учитывайте примечание к базе данных о сравнении строк.
range
Тест диапазона (включительно).
Пример:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
Эквивалент в SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Вы можете использовать range везде, где вы можете использовать BETWEEN в SQL — для дат, чисел и даже символов.
Предупреждение
Фильтрация DateTimeField с датами не будет включать элементы в последний день, поскольку границы интерпретируются как «0:00 в заданную дату». Если pub_date была DateTimeField, вышеуказанное выражение будет преобразовано в SQL следующим образом:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Как правило, вы не можете смешивать даты и datetime.
date
Для полей datetime значение преобразуется в дату. Позволяет цепочку дополнительных поисков по полям. Принимает значение даты.
Пример:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(Для этого поиска не предоставлен эквивалент SQL, так как реализация соответствующего запроса различается в разных базах данных.)
Когда USE_TZ имеет значение True, поля преобразуются в текущую временную зону перед фильтрацией.
year
Для полей даты и datetime точное совпадение года. Позволяет цепочку дополнительных поисков по полям. Принимает целое число года.
Пример:
Entry.objects.filter(pub_date__year=2005) Entry.objects.filter(pub_date__year__gte=2005)
Эквивалент в SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31'; SELECT ... WHERE pub_date >= '2005-01-01';
(Точная синтаксическая конструкция SQL варьируется в зависимости от базы данных.)
Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией.
month
Для полей даты и datetime точное совпадение месяца. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 1 (январь) до 12 (декабрь).
Пример:
Entry.objects.filter(pub_date__month=12) Entry.objects.filter(pub_date__month__gte=6)
Эквивалент в SQL:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(Точная синтаксическая конструкция SQL варьируется в зависимости от базы данных.)
Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Требуются определения временных зон в базе данных.
day
Для полей даты и datetime точное совпадение дня. Позволяет цепочку дополнительных поисков по полям. Принимает целое число дня.
Пример:
Entry.objects.filter(pub_date__day=3) Entry.objects.filter(pub_date__day__gte=3)
Эквивалент в SQL:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(Точная синтаксическая конструкция SQL варьируется в зависимости от базы данных.)
Это будет соответствовать любым записям с pub_date на третье число месяца, таким как 3 января, 3 июля и т. д.
Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Требуются определения временных зон в базе данных.
week
Для полей даты и datetime возвращает номер недели (1-52 или 53) в соответствии со ISO-8601, т. е. недели начинаются с понедельника, а первая неделя начинается в четверг или раньше.
Пример:
Entry.objects.filter(pub_date__week=52) Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(Для этого поиска не предоставлен эквивалент SQL, так как реализация соответствующего запроса различается в разных базах данных.)
Когда USE_TZ имеет значение True, поля преобразуются в текущую временную зону перед фильтрацией.
week_day
Для полей даты и datetime соответствие «дню недели». Позволяет цепочку дополнительных поисков по полям.
Принимает целое число, представляющее день недели от 1 (воскресенье) до 7 (суббота).
Пример:
Entry.objects.filter(pub_date__week_day=2) Entry.objects.filter(pub_date__week_day__gte=2)
(Для этого поиска не предоставлен эквивалент SQL, так как реализация соответствующего запроса различается в разных базах данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date, которая приходится на понедельник (день 2 недели), независимо от месяца или года, в котором она происходит. Дни недели индексируются с днем 1, являющимся воскресеньем, и днем 7, являющимся субботой.
Когда USE_TZ имеет значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Требуются определения временных зон в базе данных.
time
Для полей datetime значение преобразуется во время. Позволяет цепочку дополнительных поисков по полям. Принимает значение datetime.time.
Пример:
Entry.objects.filter(pub_date__time=datetime.time(14, 30)) Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(Для этого поиска не предоставлен эквивалент SQL, так как реализация соответствующего запроса различается в разных базах данных.)
Когда USE_TZ имеет значение True, поля преобразуются в текущую временную зону перед фильтрацией.
hour
Для полей datetime и time точное совпадение часа. Позволяет цепочку дополнительных поисков по полям. Принимает целое число от 0 до 23.
Пример:
Event.objects.filter(timestamp__hour=23) Event.objects.filter(time__hour=5) Event.objects.filter(timestamp__hour__gte=12)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Для полей datetime, когда USE_TZ равно True, значения преобразуются в текущую часовую зону перед фильтрацией.
minute
Для полей datetime и time — точное совпадение минут. Позволяет объединять дополнительные поиски по полям. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__minute=29) Event.objects.filter(time__minute=46) Event.objects.filter(timestamp__minute__gte=29)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Для полей datetime, когда USE_TZ равно True, значения преобразуются в текущую часовую зону перед фильтрацией.
second
Для полей datetime и time — точное совпадение секунд. Позволяет объединять дополнительные поиски по полям. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__second=31) Event.objects.filter(time__second=2) Event.objects.filter(timestamp__second__gte=31)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(Точный синтаксис SQL зависит от каждого движка базы данных.)
Для полей datetime, когда USE_TZ равно True, значения преобразуются в текущую часовую зону перед фильтрацией.
isnull
Принимает либо True, либо False, что соответствует SQL-запросам IS NULL и IS NOT NULL соответственно.
Пример:
Entry.objects.filter(pub_date__isnull=True)
Эквивалент SQL:
SELECT ... WHERE pub_date IS NULL;
search
Устарело начиная с версии 1.10: См. примечания к релизу 1.10 о том, как его заменить.
Булево полнотекстовый поиск, использующий полнотекстовый индексирование. Это похоже на contains, но значительно быстрее благодаря полнотекстовому индексированию.
Пример:
Entry.objects.filter(headline__search="+Django -jazz Python")
Эквивалент SQL:
SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);
Обратите внимание, что это доступно только в MySQL и требует прямого вмешательства в базу данных для добавления полнотекстового индекса. По умолчанию Django использует режим BOOLEAN для полнотекстовых поисков. Дополнительные сведения см. в документации MySQL по полнотекстовому поиску с булевыми операторами.
regex
Чувствительный к регистру поиск по регулярному выражению.
Синтаксис регулярных выражений соответствует используемому движку базы данных. В случае SQLite, у которого нет встроенной поддержки регулярных выражений, эта функция предоставляется пользователем (Python) определённой функцией REGEXP, и синтаксис регулярных выражений, следовательно, соответствует синтаксису модуля 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 приведут к ошибке NotImplementedError.
Примечание
Функции агрегации возвращают None, когда используются с пустым QuerySet. Например, функция агрегации Sum возвращает None вместо 0, если QuerySet не содержит записей. Исключение составляет функция Count, которая возвращает 0, если QuerySet пуста.
Все агрегаты имеют общие параметры:
expression
Строка, ссылающаяся на поле модели, или выражение запроса.
output_field
Необязательный аргумент, представляющий поле модели возвращаемого значения
Примечание
При объединении нескольких типов полей Django может определить output_field только в том случае, если все поля одного типа. В противном случае вы должны указать output_field самостоятельно.
**extra
Ключевые аргументы, которые могут предоставить дополнительный контекст для SQL, генерируемого агрегатом.
Avg
-
class Avg(expression, output_field=FloatField(), **extra)[source] -
Возвращает среднее значение заданного выражения, которое должно быть числовым, если не указано иное
output_field.- По умолчанию псевдоним:
<field>__avg - Тип возвращаемого значения:
float(или тип указанногоoutput_field)
- По умолчанию псевдоним:
Count
-
class Count(expression, distinct=False, **extra)[source] -
Возвращает количество объектов, связанных через указанное выражение.
- По умолчанию псевдоним:
<field>__count - Тип возвращаемого значения:
int
Имеет один необязательный аргумент:
-
distinct -
Если
distinct=True, счёт будет включать только уникальные экземпляры. Это эквивалент SQL-запросаCOUNT(DISTINCT <field>). Значение по умолчанию —False.
- По умолчанию псевдоним:
Max
-
class Max(expression, output_field=None, **extra)[source] -
Возвращает максимальное значение заданного выражения.
- По умолчанию псевдоним:
<field>__max - Тип возвращаемого значения: такой же, как у входного поля, или
output_field, если задан
- По умолчанию псевдоним:
Min
-
class Min(expression, output_field=None, **extra)[source] -
Возвращает минимальное значение заданного выражения.
- По умолчанию псевдоним:
<field>__min - Тип возвращаемого значения: такой же, как у входного поля, или
output_field, если задан
- По умолчанию псевдоним:
StdDev
-
class StdDev(expression, sample=False, **extra)[source] -
Возвращает стандартное отклонение данных в заданном выражении.
- По умолчанию псевдоним:
<field>__stddev - Тип возвращаемого значения:
float
Имеет один необязательный аргумент:
-
sample -
По умолчанию
StdDevвозвращает стандартное отклонение генеральной совокупности. Однако, еслиsample=True, возвращаемое значение будет стандартным отклонением выборки.
SQLite
SQLite не предоставляет
StdDev«из коробки». Реализация доступна в виде модуля расширения для SQLite. Обратитесь к документации по SQlite за инструкциями по получению и установке этого расширения. - По умолчанию псевдоним:
Sum
-
class Sum(expression, output_field=None, **extra)[source] -
Вычисляет сумму всех значений заданного выражения.
- По умолчанию псевдоним:
<field>__sum - Тип возвращаемого значения: такой же, как у входного поля, или
output_field, если задан
- По умолчанию псевдоним:
Variance
-
class Variance(expression, sample=False, **extra)[source] -
Возвращает дисперсию данных в предоставленном выражении.
- Значение по умолчанию:
<field>__variance - Тип возвращаемого значения:
float
Имеет один необязательный аргумент:
-
sample -
По умолчанию,
Varianceвозвращает дисперсию генеральной совокупности. Однако, еслиsample=True, возвращаемое значение будет выборочной дисперсией.
SQLite
SQLite не предоставляет
Varianceнапрямую. Реализация доступна как модуль расширения для SQLite. Обратитесь к документации SQlite за инструкциями по получению и установке этого расширения. - Значение по умолчанию:
Инструменты, связанные с запросами
Q() объекты
-
class Q[source]
Объект Q(), подобно объекту F, инкапсулирует SQL-выражение в объекте Python, который можно использовать в операциях, связанных с базой данных.
В общем случае, Q() objects позволяют определять и повторно использовать условия. Это позволяет создавать сложные запросы к базе данных с использованием | (OR) и & (AND) операторов; в частности, иначе невозможно использовать OR в QuerySets.
Prefetch() объекты
-
class Prefetch(lookup, queryset=None, to_attr=None)[source]
Объект Prefetch() можно использовать для управления операциями prefetch_related().
Аргумент lookup описывает отношения для следования и работает так же, как строковые поиски, переданные в prefetch_related(). Например:
>>> from django.db.models import Prefetch
>>> Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch('choice_set')).all()
<QuerySet [<Question: What's up?>]>
Аргумент queryset предоставляет базовый QuerySet для заданного поиска. Это полезно для дальнейшего фильтрации операции предварительной выборки или для вызова select_related() из предварительно выбранного отношения, что еще больше уменьшает количество запросов:
>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
<QuerySet [<Choice: The sky>]>
>>> prefetch = Prefetch('choice_set', queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: The sky>]>
Аргумент to_attr устанавливает результат операции предварительной выборки в пользовательское свойство:
>>> prefetch = Prefetch('choice_set', queryset=voted_choices, to_attr='voted_choices')
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
<QuerySet [<Choice: The sky>]>
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
Примечание
При использовании to_attr предварительно выбранный результат хранится в списке. Это может значительно ускорить работу по сравнению с традиционными prefetch_related вызовами, которые хранят кэшированный результат внутри объекта QuerySet.
prefetch_related_objects()
Предварительно выбирает указанные поиски по итерируемому набору экземпляров модели. Это полезно в коде, который получает список экземпляров модели, а не QuerySet; например, при извлечении моделей из кэша или при их ручном создании.
Передайте итерируемый набор экземпляров модели (все должны быть одного класса) и поиски или объекты Prefetch, которые вы хотите предварительно выбрать. Например:
>>> from django.db.models import prefetch_related_objects >>> restaurants = fetch_top_restaurants_from_cache() # A list of Restaurants >>> prefetch_related_objects(restaurants, 'pizzas__toppings')
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.11/ref/models/querysets/