Справочник по API QuerySet
В данном документе описаны подробности API QuerySet. Он основан на материалах, представленных в руководствах по моделям и запросам к базе данных, поэтому, вероятно, вам нужно будет прочитать и понять эти документы перед чтением этого.
В этом справочнике мы будем использовать примеры моделей Weblog, представленные в руководстве по запросам к базе данных.
Когда QuerySet оцениваются
Внутренне, QuerySet может быть построен, отфильтрован, разделен и вообще передан без фактического обращения к базе данных. Никакой активности базы данных не происходит до тех пор, пока вы не выполните действия для оценки запроса.
Вы можете оценить QuerySet следующими способами:
-
Итерация.
QuerySetявляется итерируемым, и он выполняет свой запрос к базе данных в первый раз, когда вы итерируетесь по нему. Например, это выведет заголовок всех записей в базе данных:for e in Entry.objects.all(): print(e.headline)Примечание: Не используйте этот метод, если все, что вам нужно, это определить, существует ли хотя бы один результат. Более эффективно использовать
exists(). -
Разрезание. Как объясняется в Ограничение QuerySet,
QuerySetможно разделить, используя синтаксис срезов массивов Python. Разрезание неоцененногоQuerySetобычно возвращает другой неоцененныйQuerySet, но Django выполнит запрос к базе данных, если вы используете параметр «шаг» синтаксиса среза, и вернёт список. Разрезание оцененногоQuerySetтакже возвращает список.Также обратите внимание, что даже если при разрезании неоценённого
QuerySetвозвращается другой неоценённыйQuerySet, дальнейшее его изменение (например, добавление дополнительных фильтров или изменение сортировки) не допускается, поскольку это не хорошо переводится на SQL и не имеет ясного смысла. - Сериализация/Кэширование. Подробности о том, что происходит при сериализации QuerySet, см. в следующем разделе. Важно для этой секции, что результаты считываются из базы данных.
-
repr().
QuerySetоценивается при вызовеrepr()на нём. Это сделано для удобства в интерактивном интерпретаторе Python, чтобы вы могли сразу увидеть результаты при интерактивном использовании API. -
len().
QuerySetоценивается при вызовеlen()на нём. Это, как можно предположить, возвращает длину списка результатов.Примечание: Если вам нужно только определить количество записей в наборе (а не сами объекты), гораздо эффективнее обработать счёт на уровне базы данных, используя SQL
SELECT COUNT(*). Django предоставляет методcount()именно для этого. -
list(). Принудительно оценить
QuerySet, вызвавlist()на нём. Например:entry_list = list(Entry.objects.all())
-
bool(). Проверка
QuerySetв контексте булевого значения, например, с использованиемbool(),or,andили оператораif, вызовет выполнение запроса. Если существует хотя бы один результат, тоQuerySetявляетсяTrue, в противном случаеFalse. Например:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")Примечание: Если вам нужно только определить, существует ли хотя бы один результат (и вам не нужны сами объекты), более эффективно использовать
exists().
Сериализация QuerySet
Если вы pickle QuerySet, это принудительно загрузит все результаты в память перед сериализацией. Сериализация обычно используется как прелюдия к кэшированию, и когда кэшированный QuerySet перезагружается, вы хотите, чтобы результаты уже были доступны и готовы к использованию (считывание из базы данных может занять некоторое время, что сведёт на нет цель кэширования). Это означает, что когда вы десериализуете QuerySet, он содержит результаты на момент сериализации, а не результаты, которые в настоящее время находятся в базе данных.
Если вы хотите сериализовать только необходимую информацию для повторного создания QuerySet из базы данных в будущем, сериализуйте атрибут query QuerySet. Затем вы можете воссоздать исходный QuerySet (без загрузки результатов) с помощью кода подобного этому:
>>> import pickle >>> query = pickle.loads(s) # Assuming 's' is the pickled string. >>> qs = MyModel.objects.all() >>> qs.query = query # Restore the original 'query'.
Атрибут query — это непрозрачный объект. Он представляет собой внутреннее представление построения запроса и не является частью публичного API. Тем не менее, безопасно (и полностью поддерживается) сериализовать и десериализовать содержимое атрибута, как описано здесь.
QuerySet API
Вот формальное объявление QuerySet:
-
class QuerySet(model=None, query=None, using=None)[source] -
Обычно при взаимодействии с
QuerySetвы будете использовать его, цепляя фильтры. Для этого большинство методовQuerySetвозвращают новые QuerySet. Эти методы подробно описаны далее в этой секции.Класс
QuerySetимеет два публичных атрибута, которые вы можете использовать для интроспекции:-
ordered -
TrueеслиQuerySetотсортирован — т. е. имеет клаузуorder_by()или стандартную сортировку по модели.Falseв противном случае.
-
db -
База данных, которая будет использоваться, если этот запрос будет выполнен сейчас.
Примечание
Параметр
queryдляQuerySetсуществует для того, чтобы специализированные подклассы запросов могли восстановить внутреннее состояние запроса. Значение параметра — это непрозрачное представление этого состояния запроса и не является частью публичного 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)
Возвращает новый QuerySet с использованием SELECT DISTINCT в запросе SQL. Это исключает дублирующиеся строки из результатов запроса.
По умолчанию, QuerySet не будет исключать дублирующиеся строки. На практике это редко проблема, потому что простые запросы, такие как Blog.objects.all(), не создают возможности получить дублирующиеся строки результатов. Однако, если ваш запрос охватывает несколько таблиц, возможно получение дублирующихся результатов при оценке QuerySet. Именно тогда вам понадобится distinct().
Примечание
Любые поля, используемые в вызове order_by(), включаются в SQL SELECT столбцы. Это иногда может привести к неожиданным результатам при использовании в сочетании с distinct(). Если вы сортируете по полям из связанной модели, эти поля будут добавлены в выбранные столбцы, и они могут заставить строки, которые в противном случае были бы дубликатами, выглядеть отличными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они нужны только для поддержки сортировки), иногда кажется, что возвращаются не уникальные результаты.
Аналогично, если вы используете запрос values() для ограничения выбираемых столбцов, столбцы, используемые в любом вызове order_by() (или стандартной сортировки модели), всё ещё будут участвовать и могут повлиять на уникальность результатов.
Мораль заключается в том, что если вы используете distinct(), будьте осторожны при сортировке по связанным моделям. Точно так же, при использовании distinct() и values() вместе, будьте внимательны при сортировке по полям, не входящим в вызов values().
Только в PostgreSQL вы можете передать позиционные аргументы (*fields) для указания имен полей, к которым должно применяться DISTINCT. Это переводится в запрос SQL SELECT DISTINCT ON. Вот в чём разница. При обычном вызове distinct(), база данных сравнивает каждое поле в каждой строке при определении того, какие строки являются уникальными. При вызове distinct() с указанными именами полей база данных будет сравнивать только указанные имена полей.
Примечание
Когда вы указываете имена полей, вы обязательно должны предоставить order_by() в QuerySet, и поля в order_by() должны начинаться с полей в distinct(), в том же порядке.
Например, SELECT DISTINCT ON (a) даёт вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите произвольную строку.
Примеры (после первого будут работать только в PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]
>>> Entry.objects.order_by('blog').distinct('blog')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]
>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]
Примечание
Обратите внимание, что order_by() использует любые значения по умолчанию для упорядочивания связанных моделей, которые были определены. Возможно, вам придётся явно указать порядок сортировки по отношению _id или связанному полю, чтобы убедиться, что выражения DISTINCT ON совпадают с выражениями в начале ORDER BY условия. Например, если модель Blog определяет ordering по name:
Entry.objects.order_by('blog').distinct('blog')
…это не сработает, потому что запрос будет отсортирован по blog__name, что не соответствует выражению DISTINCT ON. Вам нужно явно указать порядок сортировки по отношению _id (в данном случае blog_id) или по связанному полю (blog__pk) для обеспечения соответствия обоих выражений.
values()
-
values(*fields, **expressions)
Возвращает QuerySet , который возвращает словари, а не экземпляры моделей, при использовании в качестве итерируемого объекта.
Каждый из этих словарей представляет объект, ключи которого соответствуют именам атрибутов объектов модели.
В этом примере сравниваются словари values() с обычными объектами модели:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Метод values() принимает необязательные позиционные аргументы, *fields, которые указывают имена полей, до которых следует ограничить SELECT . Если вы указываете поля, каждый словарь будет содержать только ключи/значения полей, которые вы указали. Если вы не указываете поля, каждый словарь будет содержать ключ и значение для каждого поля в таблице базы данных.
Пример:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Метод values() также принимает необязательные ключевые аргументы, **expressions, которые передаются в annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
Агрегация в 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, named=False)
Это похоже на values() , за исключением того, что вместо словарей возвращаются кортежи при итерации. Каждый кортеж содержит значение из соответствующего поля или выражения, переданного в вызов values_list() — первый элемент — первое поле и т.д. Например:
>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>
Если вы передаёте только одно поле, вы также можете передать параметр flat. Если True, это означает, что возвращаемые результаты — это отдельные значения, а не кортежи длиной в один элемент. Пример позволит чётче увидеть разницу:
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
Ошибка передать flat когда присутствует более одного поля.
Вы можете передать named=True , чтобы получить результаты как namedtuple():
>>> Entry.objects.values_list('id', 'headline', named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
Использование именованного кортежа может сделать использование результатов более понятным, за счёт незначительного снижения производительности для преобразования результатов в именованный кортеж.
Если вы не передадите никаких значений в values_list(), то будут возвращены все поля в модели в порядке их объявления.
Общая потребность — получить значение определённого поля определённого экземпляра модели. Для этого используйте values_list() и вызов get().
>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'
values() и values_list() предназначены в качестве оптимизаций для конкретного случая использования: получение подмножества данных без издержек создания экземпляра модели. Эта метафора распадается при работе с множественными связями и другими многозначными отношениями (такими как отношение один-ко-многим обратного внешнего ключа), поскольку предположение «одна строка, один объект» не выполняется.
Например, обратите внимание на поведение при запросе через ManyToManyField:
>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
Авторы с несколькими записями появляются несколько раз, а авторы без записей имеют None для заголовка записи.
Аналогично, при запросе обратного внешнего ключа, None появляется для записей, у которых нет автора:
>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
Добавлена поддержка выражений в *fields.
Добавлен параметр named.
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()
Возвращает набор запросов, который будет «следовать» за связями внешних ключей, выбирая дополнительные данные связанных объектов при выполнении запроса. Это улучшение производительности, которое приводит к одному более сложному запросу, но означает, что последующее использование связей внешних ключей не потребует запросов к базе данных.
Следующие примеры иллюстрируют разницу между обычными и 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())
Вы можете следовать внешним ключам аналогично запросам. Если у вас есть следующие модели:
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:
# Hits the database with joins to the author and hometown tables.
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.
# Without select_related()...
b = Book.objects.get(id=4) # Hits the database.
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() без аргументов. Это позволит следовать всем непустым внешним ключам, которые можно найти — пустые внешние ключи необходимо указать. В большинстве случаев это не рекомендуется, так как, вероятно, это сделает базовый запрос более сложным и вернет больше данных, чем фактически необходимо.
Если вам нужно очистить список связанных полей, добавленных предыдущими вызовами select_related для QuerySet, вы можете передать None в качестве параметра:
>>> without_relations = queryset.select_related(None)
Цепочка вызовов select_related работает аналогично другим методам — то есть select_related('foo', 'bar') эквивалентно select_related('foo').select_related('bar').
prefetch_related()
Возвращает набор запросов, который автоматически извлекает связанные объекты для каждого из указанных поисков в одной группе.
Это имеет аналогичную цель, что и 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):
return "%s (%s)" % (
self.name,
", ".join(topping.name for topping in self.toppings.all()),
)
и запустите:
%%%CODE_BLOCK_427%%>Проблема в том, что каждый раз, когда Pizza.__str__() запрашивает self.toppings.all(), ему нужно обращаться к базе данных, поэтому Pizza.objects.all() будет выполнять запрос к таблице Toppings для каждого элемента в пицце 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-инъекций из-за кавычек вокруг %s:
"select col from sometable where othercol = '%s'" # unsafe!
Вы можете узнать больше о том, как работает защита от SQL-инъекций в Django защита от SQL-инъекций.
По определению, эти дополнительные запросы могут быть не портативными для разных движков баз данных (поскольку вы явно пишете код SQL) и нарушают принцип DRY, поэтому следует избегать их, если это возможно.
Укажите один или несколько из params, select, where или tables. Ни один из аргументов не является обязательным, но вы должны использовать хотя бы один из них.
-
selectАргумент
selectпозволяет добавлять дополнительные поля вSELECTусловие. Он должен быть словарем, сопоставляющим имена атрибутов с SQL-фрагментами, используемыми для расчёта этого атрибута.Пример:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})В результате каждый объект
Entryбудет иметь дополнительный атрибут,is_recent, логическое значение, представляющее, больше ли дата записиpub_dateчем 1 января 2006 года.Django вставляет данный SQL-фрагмент непосредственно в
SELECTоператор, поэтому результирующий SQL-запрос в вышеприведённом примере будет чем-то вроде:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Следующий пример более сложный; он выполняет подзапрос, чтобы предоставить каждому объекту
Blogатрибутentry_count, целое число — количество связанных объектовEntry:Blog.objects.extra( select={ 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' }, )В данном случае мы используем тот факт, что запрос уже будет содержать таблицу
blog_blogв своёмFROMусловии.Результат SQL в вышеприведённом примере будет:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Обратите внимание, что скобки, необходимые для большинства движков баз данных вокруг подзапросов, не требуются в
selectусловиях Django. Также обратите внимание, что некоторые бэкэнды баз данных, такие как некоторые версии MySQL, не поддерживают подзапросы.В некоторых редких случаях вам может потребоваться передавать параметры в SQL-фрагменты в
extra(select=...). Для этой цели используйте параметрselect_params. Поскольку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. Вы можете вручную добавлять таблицы в условие SQLFROMс помощьюtables.whereиtablesоба принимают список строк. Всеwhereпараметры объединяются с другими критериями поиска с помощью логического «И».Пример:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
… приблизительно переводится на следующий SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Будьте осторожны при использовании параметра
tables, если вы указываете таблицы, которые уже используются в запросе. Когда вы добавляете дополнительные таблицы через параметрtables, Django предполагает, что вы хотите включить эту таблицу ещё раз, если она уже включена. Это создаёт проблему, так как имя таблицы тогда будет получено псевдоним. Если таблица встречается несколько раз в SQL-запросе, для второй и последующих появлений необходимо использовать псевдонимы, чтобы база данных могла их различать. Если вы ссылаетесь на дополнительную таблицу, добавленную в параметрwhere, это приведёт к ошибкам.Обычно вы будете добавлять только дополнительные таблицы, которые не появляются в запросе. Однако, если произойдёт описанный выше случай, есть несколько решений. Сначала, посмотрите, сможете ли вы обойтись без включения дополнительной таблицы и использовать ту, что уже есть в запросе. Если это невозможно, поместите вызов
extra()в начало построения набора запросов, так чтобы ваша таблица была первым использованием этой таблицы. Наконец, если всё остальное не сработает, посмотрите на сгенерированный запрос и перепишите добавлениеwhereдля использования псевдонима, присвоенного дополнительной таблице. Псевдоним будет таким же каждый раз, когда вы создаёте набор запросов таким же образом, поэтому вы можете полагаться на то, что имя псевдонима не изменится. -
order_byЕсли вам нужно отсортировать результирующий набор запросов, используя некоторые из новых полей или таблиц, добавленных через
extra(), используйте параметрorder_byдляextra()и передайте последовательность строк. Эти строки должны быть полями модели (как в обычном методеorder_by()наборах запросов), в форматеtable_name.column_nameили псевдонимом столбца, который вы указали в параметреselectдляextra().Например:
q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) q = q.extra(order_by = ['-is_recent'])Это отсортирует все элементы, для которых
is_recentравно истинному, в начало набора результатов (Trueотсортируется передFalseв порядке убывания).Это также показывает, что вы можете делать несколько вызовов
extra()и он будет вести себя ожидаемо (добавляя новые ограничения каждый раз). -
paramsВ описанном выше параметре
whereможно использовать стандартные подстановки строк Python для баз данных —'%s'для указания параметров, которые движок базы данных должен автоматически привести к кавычкам. Параметрparams— это список дополнительных параметров, подлежащих замене.Пример:
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Всегда используйте
paramsвместо непосредственного внедрения значений вwhere, потому чтоparamsгарантирует, что значения будут заключены в кавычки в соответствии с вашим конкретным бэкэндом. Например, кавычки будут экранированы правильно.Плохо:
Entry.objects.extra(where=["headline='Lennon'"])
Хорошо:
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Предупреждение
Если вы выполняете запросы в MySQL, обратите внимание, что неявное приведение типов в MySQL может привести к неожиданным результатам при смешивании типов. Если вы запрашиваете столбец строкового типа, но с целочисленным значением, MySQL приведёт типы всех значений в таблице к целочисленному типу перед выполнением сравнения. Например, если ваша таблица содержит значения 'abc', 'def', и вы запрашиваете WHERE mycolumn=0, обе строки будут соответствовать. Чтобы предотвратить это, выполните правильное приведение типов перед использованием значения в запросе.
defer()
-
defer(*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, of=())
Возвращает набор запросов, который будет блокировать строки до конца транзакции, генерируя 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.
По умолчанию select_for_update() блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанных в select_related(), заблокированы помимо строк модели набора запросов. Если этого не нужно, укажите связанные объекты, которые вы хотите заблокировать, в select_for_update(of=(...)) с тем же синтаксисом полей, что и в select_related(). Используйте значение 'self' для ссылки на модель набора запросов.
Вы не можете использовать select_for_update() для отношений с возможностью значения NULL:
>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
Чтобы избежать этого ограничения, можно исключить нулевые объекты, если они вам не нужны:
>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
В настоящее время postgresql, oracle, и mysql бэкэнды баз данных поддерживают select_for_update(). Однако MySQL не поддерживает параметры nowait, skip_locked, и of.
Передача nowait=True, skip_locked=True, или of к select_for_update() с помощью бэкэндов баз данных, не поддерживающих эти параметры, таких как MySQL, вызовет NotSupportedError. Это предотвращает непредвиденное блокирование.
Оценивание набора запросов с select_for_update() в режиме autocommit на бэкендах, поддерживающих SELECT ... FOR UPDATE, является ошибкой TransactionManagementError, поскольку строки не заблокированы в этом случае. Если это разрешено, это способствовало бы порче данных и могло быть легко вызвано кодом, который ожидает выполнения вне транзакции.
Использование select_for_update() на бэкендах, которые не поддерживают SELECT ... FOR UPDATE (например, SQLite), не повлияет. SELECT ... FOR UPDATE не будет добавлен в запрос, и ошибка не будет поднята, если select_for_update() используется в режиме autocommit.
Предупреждение
Хотя select_for_update() обычно терпит неудачу в режиме autocommit, поскольку TestCase автоматически оборачивает каждый тест в транзакцию, вызов select_for_update() в TestCase даже за пределами блока atomic() пройдёт (возможно, неожиданно), не подняв TransactionManagementError. Для правильного тестирования select_for_update() следует использовать TransactionTestCase.
Определённые выражения могут быть не поддерживаемы
PostgreSQL не поддерживает select_for_update() с выражениями Window.
Добавлен аргумент skip_locked.
Добавлен аргумент of.
raw()
-
raw(raw_query, params=None, translations=None)
Принимает сырой SQL-запрос, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet. Этот экземпляр RawQuerySet можно перебирать так же, как и обычный набор QuerySet, чтобы получить экземпляры объектов.
Для получения дополнительной информации см. Выполнение сырых SQL-запросов.
Предупреждение
raw() всегда инициирует новый запрос и не учитывает предыдущие фильтры. Поэтому его обычно следует вызывать из Manager или из свежего экземпляра QuerySet.
Методы, которые не возвращают наборы запросов
Следующие 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, этот метод подвержен гонке, что может привести к одновременной вставке нескольких строк с одинаковыми параметрами.
Если вы используете 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(), этот метод подвержен гонке, которая может привести к одновременной вставке нескольких строк, если уникальность не гарантируется на уровне базы данных.
Как и get_or_create() и create(), если вы используете вручную заданные первичные ключи и объект должен быть создан, но ключ уже существует в базе данных, поднимается исключение IntegrityError.
Добавлена поддержка вызываемых значений в 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). - Он не работает с отношениями "многие ко многим".
-
Он преобразует
objsв список, что полностью вычисляетobjs, если это генератор. Преобразование позволяет просматривать все объекты, поэтому объекты с вручную заданным первичным ключом могут быть вставлены в первую очередь. Если вы хотите вставлять объекты партиями, не вычисляя весь генератор сразу, вы можете использовать этот приём, если у объектов нет вручную заданных первичных ключей:from itertools import islice batch_size = 100 objs = (Entry(headline='Test %s' % i) for i in range(1000)) while True: batch = list(islice(objs, batch_size)) if not batch: break Entry.objects.bulk_create(batch, batch_size)
Параметр batch_size управляет количеством объектов, создаваемых в одном запросе. По умолчанию все объекты создаются в одной партии, за исключением SQLite, где по умолчанию используется не более 999 переменных в запросе.
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() будет быстрее).
Обратите внимание, что если вам нужно количество элементов в QuerySet и вы также получаете экземпляры модели из него (например, итерируя по нему), то, вероятно, эффективнее использовать len(queryset), который не вызовет дополнительный запрос к базе данных, в отличие от count().
in_bulk()
-
in_bulk(id_list=None, field_name='pk')
Принимает список значений поля (id_list) и field_name для этих значений и возвращает словарь, сопоставляющий каждое значение с экземпляром объекта с заданным значением поля. Если id_list не указано, возвращаются все объекты в наборе запросов. field_name должно быть уникальным полем, и по умолчанию это первичный ключ.
Пример:
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
{'beatles_blog': <Blog: Beatles Blog>}
Если вы передадите in_bulk() пустой список, вы получите пустой словарь.
Был добавлен параметр field_name.
iterator()
-
iterator(chunk_size=2000)
Вычисляет QuerySet (выполняя запрос) и возвращает итератор (см. PEP 234) по результатам. Итератор обычно кэширует свои результаты внутри себя, так что повторные вычисления не приводят к дополнительным запросам. В отличие от этого, iterator() будет читать результаты непосредственно, без кэширования на уровне QuerySet (внутри, по умолчанию, итератор вызывает iterator() и кэширует возвращаемое значение). Для набора запросов, который возвращает большое количество объектов, которые вам нужно получить только один раз, это может улучшить производительность и значительно сократить потребление памяти.
Обратите внимание, что использование iterator() на наборе запросов, который уже был вычислен, заставит его перевычисляться, повторив запрос.
Также использование iterator() игнорирует предыдущие вызовы prefetch_related(), так как эти два оптимизация не имеют смысла вместе.
В зависимости от базы данных, результаты запроса либо загружаются все сразу, либо передаются из базы данных с использованием серверных курсоров.
С серверными курсорами
Oracle и PostgreSQL используют серверные курсоры для потоковой передачи результатов из базы данных без загрузки всего набора результатов в память.
Драйвер Oracle всегда использует серверные курсоры.
С серверными курсорами параметр chunk_size указывает количество результатов, которые необходимо кэшировать на уровне драйвера базы данных. Извлечение больших кусков уменьшает количество обращений между драйвером базы данных и базой данных, но за счет увеличения потребления памяти.
В PostgreSQL серверные курсоры будут использоваться только тогда, когда параметр DISABLE_SERVER_SIDE_CURSORS имеет значение False. Обратитесь к пулу транзакций и серверным курсорам, если вы используете пул соединений, настроенный в режиме пула транзакций. Когда серверные курсоры отключены, поведение аналогично базам данных, которые не поддерживают серверные курсоры.
Без серверных курсоров
MySQL и SQLite не поддерживают потоковую передачу результатов, поэтому драйверы баз данных Python загружают весь набор результатов в память. Затем набор результатов преобразуется в объекты строк Python адаптером базы данных с помощью метода fetchmany(), определенного в PEP 249.
Параметр chunk_size управляет размером пакетов, которые Django извлекает из драйвера базы данных. Более крупные пакеты уменьшают издержки на взаимодействие с драйвером базы данных за счет небольшого увеличения потребления памяти.
Значение по умолчанию параметра chunk_size, 2000, взято из расчета на списке рассылки psycopg:
Была добавлена поддержка серверных курсоров в PostgreSQL.
Был добавлен параметр chunk_size.
latest()
-
latest(*fields)
Возвращает последний объект в таблице на основе заданного поля(ей).
Этот пример возвращает самый последний Entry в таблице по полю pub_date.
Entry.objects.latest('pub_date')
Вы также можете выбрать последний по нескольким полям. Например, чтобы выбрать Entry с самым ранним expire_date, когда две записи имеют одинаковое значение поля pub_date.
Entry.objects.latest('pub_date', '-expire_date')
Отрицательный знак в '-expire_date' означает сортировку expire_date в понижающем порядке. Так как latest() получает последний результат, выбирается Entry с самым ранним expire_date.
Если в Meta вашей модели указано get_latest_by, вы можете опустить любые аргументы в earliest() или latest(). Поля, указанные в get_latest_by, будут использоваться по умолчанию.
Как и get(), earliest() и latest() генерируют исключение DoesNotExist, если нет объекта с заданными параметрами.
Обратите внимание, что earliest() и latest() существуют только для удобства и читаемости.
Добавлена поддержка нескольких аргументов.
earliest() и latest() могут возвращать экземпляры с нулевыми датами.
Поскольку сортировка делегируется базе данных, результаты по полям, допускающим нулевые значения, могут быть отсортированы по-разному, если вы используете разные базы данных. Например, PostgreSQL и MySQL сортируют нулевые значения так, как будто они больше, чем ненулевые значения, в то время как SQLite делает наоборот.
Возможно, вам захочется отфильтровать нулевые значения:
Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
earliest()
-
earliest(*fields)
Работает иначе, как latest(), за исключением изменения направления.
first()
-
first()
Возвращает первый объект, соответствующий набору запроса, или None, если нет соответствующего объекта. Если в наборе запросов нет определенной сортировки, то набор запросов автоматически сортируется по первичному ключу. Это может повлиять на результаты агрегации, как описано в Взаимодействии с сортировкой по умолчанию или order_by().
Пример:
p = Article.objects.order_by('title', 'pub_date').first()
Обратите внимание, что first() это удобный метод, следующий код эквивалентен приведенному выше примеру:
try:
p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
p = None
last()
-
last()
Работает как first(), но возвращает последний объект в наборе запросов.
aggregate()
-
aggregate(*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 может воспользоваться быстрым путём и удалить объекты без загрузки в память. Для больших удалений это может значительно уменьшить использование памяти. Также может быть уменьшено количество исполненных запросов.
ForeignKeys, которые установлены в 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 и не-ASCII строк имейте в виду примечание к базе данных по сравнению строк. SQLite не выполняет нечувствительное к регистру сопоставление для не-ASCII строк.
contains
Чувствительное к регистру проверка на наличие подстроки.
Пример:
Entry.objects.get(headline__contains='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline LIKE '%Lennon%';
Обратите внимание, что это будет соответствовать заголовку 'Lennon honored today', но не 'lennon
honored today'.
Пользователи SQLite
SQLite не поддерживает операторы LIKE, оператор contains работает как оператор icontains для SQLite. Подробнее см. примечание к базе данных.
icontains
Проверка нечувствительного к регистру вхождения.
Пример:
Entry.objects.get(headline__icontains='Lennon')
Эквивалент SQL:
SELECT ... WHERE headline ILIKE '%Lennon%';
Пользователи SQLite
При использовании SQLite-бекенда и строк, отличных от ASCII, учтите примечание к базе данных о сравнении строк.
in
В заданном итерируемом объекте; часто это список, кортеж или набор запросов.
Пример:
Entry.objects.filter(id__in=[1, 3, 4])
Эквивалент SQL:
SELECT ... WHERE id IN (1, 3, 4);
Также можно использовать набор запросов для динамической оценки списка значений вместо предоставления списка литеральных значений:
inner_qs = Blog.objects.filter(name__contains='Cheddar') entries = Entry.objects.filter(blog__in=inner_qs)
Этот набор запросов будет оценён как подзапрос:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Если вы передаёте в оператор поиска QuerySet, полученный с помощью values() или values_list(), вам необходимо убедиться, что из результата извлекается только одно поле. Например, это сработает (фильтрация по названиям блогов):
inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)
Этот пример вызовет исключение, так как внутренний запрос пытается извлечь два значения поля, тогда как ожидается только одно:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)
Учёт производительности
Будьте осторожны при использовании вложенных запросов и знайте характеристики производительности вашего сервера базы данных (если есть сомнения, проведите бенчмарк!). Некоторые бэкэнды баз данных, в частности MySQL, не оптимизируют вложенные запросы так хорошо. В таких случаях эффективнее извлечь список значений и затем передать его во второй запрос. То есть выполнить два запроса вместо одного:
values = Blog.objects.filter(
name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Обратите внимание на вызов list() вокруг блога QuerySet для принудительного выполнения первого запроса. Без него выполнился бы вложенный запрос, так как наборы запросов ленивы.
gt
Больше чем.
Пример:
Entry.objects.filter(id__gt=4)
Эквивалент SQL:
SELECT ... WHERE id > 4;
gte
Больше или равно.
lt
Меньше чем.
lte
Меньше или равно.
startswith
Чувствительное к регистру, начинается с.
Пример:
Entry.objects.filter(headline__startswith='Lennon')
Эквивалент SQL:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite не поддерживает чувствительные к регистру LIKE операторы; оператор startswith работает как оператор istartswith для SQLite.
istartswith
Нечувствительное к регистру, начинается с.
Пример:
Entry.objects.filter(headline__istartswith='Lennon')
Эквивалент SQL:
SELECT ... WHERE headline ILIKE 'Lennon%';
Пользователи SQLite
При использовании SQLite-бекенда и строк, отличных от ASCII, учтите примечание к базе данных о сравнении строк.
endswith
Чувствительное к регистру, заканчивается на.
Пример:
Entry.objects.filter(headline__endswith='Lennon')
Эквивалент SQL:
SELECT ... WHERE headline LIKE '%Lennon';
Пользователи SQLite
SQLite не поддерживает чувствительные к регистру LIKE операторы; оператор endswith работает как оператор iendswith для SQLite. См. документацию примечания к базе данных для получения дополнительной информации.
iendswith
Нечувствительное к регистру, заканчивается на.
Пример:
Entry.objects.filter(headline__iendswith='Lennon')
Эквивалент SQL:
SELECT ... WHERE headline ILIKE '%Lennon'
Пользователи SQLite
При использовании SQLite-бекенда и строк, отличных от ASCII, учтите примечание к базе данных о сравнении строк.
range
Проверка диапазона (включительно).
Пример:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
Эквивалент SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Вы можете использовать range в любом месте, где в SQL можно использовать BETWEEN, — для дат, чисел и даже символов.
Предупреждение
Фильтрация 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 преобразуются в текущую временную зону перед фильтрацией. Требуется определение часовых поясов в базе данных.
quarter
Для полей даты и datetime соответствие «четверти года». Позволяет цеплять дополнительные поиски по полям. Принимает целое число от 1 до 4, представляющее четверть года.
Пример получения записей во второй четверти (с 1 апреля по 30 июня):
Entry.objects.filter(pub_date__quarter=2)
(Для данного поиска не предоставлен эквивалентный фрагмент SQL-кода, так как реализация соответствующего запроса варьируется в разных базах данных.)
При USE_TZ имеющем значение True, поля datetime преобразуются в текущую временную зону перед фильтрацией. Требуется определение часовых поясов в базе данных.
time
Для полей datetime преобразует значение в время. Позволяет цеплять дополнительные поиски по полям. Принимает значение datetime.time.
Пример:
Entry.objects.filter(pub_date__time=datetime.time(14, 30)) Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(В этом запросе нет эквивалентного фрагмента кода SQL, так как реализация соответствующего запроса различается в разных базах данных.)
Когда USE_TZ равно True, поля преобразуются в текущую временную зону перед фильтрацией.
hour
Для полей 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;
regex
Чувствительный к регистру поиск по регулярному выражению.
Синтаксис регулярных выражений соответствует синтаксису используемой базы данных. В случае SQLite, у которого нет встроенной поддержки регулярных выражений, эта функция реализуется с помощью пользовательской функции REGEXP (на Python), и синтаксис регулярных выражений соответствует синтаксису модуля re Python.
Пример:
Entry.objects.get(title__regex=r'^(An?|The) +')
Эквиваленты в SQL:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Рекомендуется использовать сырые строки (например, r'foo' вместо 'foo') для передачи синтаксиса регулярных выражений.
iregex
Нечувствительный к регистру поиск по регулярному выражению.
Пример:
Entry.objects.get(title__iregex=r'^(an?|the) +')
Эквиваленты в SQL:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Функции агрегирования
Django предоставляет следующие функции агрегирования в модуле django.db.models. Подробнее о том, как использовать эти функции агрегирования, см. в руководстве по агрегированию. Изучите документацию Aggregate, чтобы узнать, как создавать свои агрегаты.
Предупреждение
SQLite не поддерживает агрегирование по полям даты/времени из коробки. Это связано с тем, что в SQLite нет встроенных полей даты/времени, и Django в настоящее время эмулирует эти функции с помощью текстового поля. Попытки использовать агрегирование по полям даты/времени в SQLite приведут к ошибке NotImplementedError.
Примечание
Функции агрегирования возвращают None, когда используются с пустым QuerySet. Например, функция агрегирования Sum возвращает None, а не 0, если QuerySet не содержит записей. Исключением является Count, которая возвращает 0, если QuerySet пуста.
У всех агрегатов есть следующие общие параметры:
expression
Строка, ссылающаяся на поле модели, или выражение запроса.
output_field
Необязательный аргумент, представляющий поле модели возвращаемого значения.
Примечание
При комбинировании нескольких типов полей Django может определить output_field только если все поля одного типа. В противном случае вы должны указать output_field самостоятельно.
filter
Необязательный Q object, используемый для фильтрации строк, которые агрегируются.
См. Условное агрегирование и Фильтрация по аннотациям для примеров использования.
**extra
Ключевые слова, которые могут предоставить дополнительный контекст для SQL, генерируемого агрегатом.
Avg
-
class Avg(expression, output_field=FloatField(), filter=None, **extra)[source] -
Возвращает среднее значение данного выражения, которое должно быть числовым, если вы не укажете другое
output_field.- По умолчанию псевдоним:
<field>__avg - Тип возвращаемого значения:
float(или тип того, чтоoutput_fieldуказано)
- По умолчанию псевдоним:
Count
-
class Count(expression, distinct=False, filter=None, **extra)[source] -
Возвращает количество объектов, связанных через указанное выражение.
- По умолчанию псевдоним:
<field>__count - Тип возвращаемого значения:
int
Имеет один необязательный аргумент:
-
distinct -
Если
distinct=True, подсчет будет включать только уникальные экземпляры. Это эквивалент SQLCOUNT(DISTINCT <field>). Значение по умолчаниюFalse.
- По умолчанию псевдоним:
Max
-
class Max(expression, output_field=None, filter=None, **extra)[source] -
Возвращает максимальное значение данного выражения.
- По умолчанию псевдоним:
<field>__max - Тип возвращаемого значения: такой же, как у входного поля, или
output_field, если он указан
- По умолчанию псевдоним:
Min
-
class Min(expression, output_field=None, filter=None, **extra)[source] -
Возвращает минимальное значение данного выражения.
- По умолчанию псевдоним:
<field>__min - Тип возвращаемого значения: такой же, как у входного поля, или
output_field, если он указан
- По умолчанию псевдоним:
StdDev
-
class StdDev(expression, sample=False, filter=None, **extra)[source] -
Возвращает стандартное отклонение данных в указанном выражении.
- По умолчанию псевдоним:
<field>__stddev - Тип возвращаемого значения:
float
Имеет один необязательный аргумент:
-
sample -
По умолчанию
StdDevвозвращает стандартное отклонение генеральной совокупности. Однако, еслиsample=True, значение возврата будет стандартным отклонением выборки.
SQLite
SQLite не предоставляет
StdDevиз коробки. Реализация доступна как модуль расширения для SQLite. Обратитесь к документации SQLite по инструкциям по получению и установке этого расширения. - По умолчанию псевдоним:
Sum
-
class Sum(expression, output_field=None, filter=None, **extra)[source] -
Вычисляет сумму всех значений данного выражения.
- По умолчанию псевдоним:
<field>__sum - Тип возвращаемого значения: такой же, как у входного поля, или
output_field, если он указан
- По умолчанию псевдоним:
Variance
-
class Variance(expression, sample=False, filter=None, **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')
FilteredRelation() объекты
-
class FilteredRelation(relation_name, *, condition=Q())[source] -
-
relation_name -
Имя поля, по которому вы хотите отфильтровать отношение.
-
condition -
Объект
Qдля управления фильтрацией.
-
FilteredRelation используется с annotate() для создания ON-запроса при выполнении JOIN. Он не действует на стандартное отношение, а на имя аннотации (pizzas_vegetarian в примере ниже).
Например, чтобы найти рестораны, которые имеют вегетарианские пиццы с 'mozzarella' в названии:
>>> from django.db.models import FilteredRelation, Q >>> Restaurant.objects.annotate( ... pizzas_vegetarian=FilteredRelation( ... 'pizzas', condition=Q(pizzas__vegetarian=True), ... ), ... ).filter(pizzas_vegetarian__name__icontains='mozzarella')
Если количество пицц велико, этот запрос работает лучше, чем:
>>> Restaurant.objects.filter( ... pizzas__vegetarian=True, ... pizzas__name__icontains='mozzarella', ... )
потому что фильтрация в WHERE-запросе первого запроса будет выполняться только на вегетарианских пиццы.
FilteredRelation не поддерживает:
-
Условий, охватывающих реляционные поля. Например:
>>> Restaurant.objects.annotate( ... pizzas_with_toppings_startswith_n=FilteredRelation( ... 'pizzas__toppings', ... condition=Q(pizzas__toppings__name__startswith='n'), ... ), ... ) Traceback (most recent call last): ... ValueError: FilteredRelation's condition doesn't support nested relations (got 'pizzas__toppings__name__startswith').
-
QuerySet.only()иprefetch_related(). -
GenericForeignKey, унаследованный от родительской модели.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.0/ref/models/querysets/