Справочник по API QuerySet
В данном документе описаны подробности API QuerySet. Он основан на материалах руководств по моделям моделей и запросам к базе данных запросов к базе данных, поэтому, вероятно, вам следует ознакомиться с этими документами перед чтением этого.
В этом справочнике мы будем использовать примеры моделей веб-журнала примеры моделей веб-журнала, представленные в руководстве по запросам к базе данных руководстве по запросам к базе данных.
При оценке 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 приведены в следующем разделе сериализация 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возвращают новые querysets. Эти методы подробно описаны позже в этом разделе.Класс
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-1-3 И чье поле headline равно “Hello”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
В терминах SQL это эквивалентно:
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
В этом примере исключаются все записи, чье поле pub_date позже 2005-1-3 ИЛИ чье поле headline равно “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, описаны в разделе Агрегационные функции ниже.
END_OF_DOCUMENT_MARKERАннотации, заданные с помощью именованных аргументов, будут использовать имя аргумента в качестве псевдонима для аннотации. Анонимные аргументы получат псевдоним, сгенерированный на основе имени агрегационной функции и поля модели, которое агрегируется. Анонимными аргументами могут быть только агрегационные выражения, ссылающиеся на одно поле. Все остальное должно быть именованным аргументом.
Например, если вы работаете со списком блогов, вы можете захотеть определить, сколько записей было сделано в каждом блоге:
>>> 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 если запрос был упорядочен каким-либо способом.
Каждый вызов order_by() очистит любое предыдущее упорядочивание. Например, этот запрос будет упорядочен по pub_date, а не по headline.
Entry.objects.order_by('headline').order_by('pub_date')
Предупреждение
Упорядочивание — это не бесплатная операция. Каждое поле, которое вы добавляете в упорядочивание, влечёт за собой затраты для вашей базы данных. Каждый внешний ключ также неявно включает все его упорядочивания по умолчанию.
Если в запросе не указано упорядочивание, результаты возвращаются из базы данных в неуказанном порядке. Гарантируется определённый порядок только тогда, когда упорядочивание производится по набору полей, уникально идентифицирующих каждый объект в результатах. Например, если поле name не уникально, упорядочивание по нему не гарантирует, что объекты с одинаковым именем всегда будут появляться в одном и том же порядке.
reverse()
-
reverse()
Используйте метод reverse() для изменения порядка возвращаемых элементов набора запроса. Вызов reverse() второй раз восстановит порядок в обычном направлении.
Чтобы получить пять последних элементов в наборе запроса, можно сделать так:
my_queryset.reverse()[:5]
Обратите внимание, что это не совсем то же самое, что срезы с конца последовательности в Python. Приведённый выше пример вернёт последний элемент первым, затем предпоследний и так далее. Если бы у нас была последовательность Python и мы посмотрели на seq[-5:], мы бы увидели пятый элемент с конца первым. Django не поддерживает такой режим доступа (срез с конца), потому что это не возможно сделать эффективно в SQL.
Также обратите внимание, что reverse() обычно следует вызывать только на наборе запросов QuerySet, который имеет определённое упорядочивание (например, при запросе к модели, которая определяет порядок по умолчанию, или при использовании order_by()). Если для данного QuerySet такого упорядочивания не определено, вызов reverse() на нём не оказывает никакого реального влияния (упорядочивание не было определено до вызова reverse(), и останется неопределённым после него).
distinct()
-
distinct(*fields)
Возвращает новый набор запросов QuerySet, который использует SELECT DISTINCT в своём SQL-запросе. Это исключает повторяющиеся строки из результатов запроса.
По умолчанию, набор запросов QuerySet не исключает повторяющиеся строки. На практике это редко является проблемой, поскольку простые запросы, такие как Blog.objects.all(), не создают возможность получения повторяющихся строк результатов. Однако, если ваш запрос охватывает несколько таблиц, возможно получение повторяющихся результатов при вычислении набора запросов QuerySet. В этом случае вам необходимо использовать distinct().
Примечание
Любые поля, используемые в вызове order_by(), включаются в столбцы SQL SELECT. Это иногда может привести к неожиданным результатам при использовании в сочетании с distinct(). Если вы упорядочиваете по полям из связанной модели, эти поля будут добавлены в выбранные столбцы, и они могут заставить строки, которые в противном случае были бы одинаковыми, выглядеть различными. Поскольку дополнительные столбцы не отображаются в возвращаемых результатах (они существуют только для поддержки упорядочивания), иногда кажется, что возвращаются не одинаковые результаты.
Аналогично, если вы используете запрос values() для ограничения выбранных столбцов, столбцы, используемые в любом вызове order_by() (или упорядочивание модели по умолчанию), всё равно будут задействованы и могут повлиять на уникальность результатов.
Мораль в том, что если вы используете distinct(), будьте осторожны с упорядочиванием по связанным моделям. Точно так же, при совместном использовании distinct() и values(), будьте осторожны при упорядочивании по полям, которые не входят в вызов values().
Только в PostgreSQL вы можете передать позиционные аргументы (*fields) для указания имён полей, к которым должно применяться DISTINCT. Это приводит к SELECT DISTINCT ON SQL-запросу. Вот в чём разница. При обычном вызове distinct(), база данных сравнивает каждое поле в каждой строке, определяя, какие строки являются различными. При вызове distinct() с указанными именами полей база данных будет сравнивать только указанные имена полей.
Примечание
При указании имён полей вы обязательно должны указать порядок (order_by()) в QuerySet, и поля в order_by() должны начинаться с полей в distinct(), в том же порядке.
Например, SELECT DISTINCT ON (a) даёт вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите произвольную строку.
Примеры (те, что после первого, будут работать только в PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]
>>> Entry.objects.order_by('blog').distinct('blog')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]
>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]
>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]
Примечание
Обратите внимание, что order_by() использует любой заданный по умолчанию порядок сортировки связанной модели. Возможно, вам придется явно отсортировать по отношению _id или связанному полю, чтобы убедиться, что DISTINCT ON выражения соответствуют тем, что в начале ORDER BY запроса. Например, если модель Blog определила ordering по name:
Entry.objects.order_by('blog').distinct('blog')
…это не сработает, потому что запрос отсортируется по blog__name, что не соответствует выражению DISTINCT ON. Вам необходимо явно отсортировать по отношению _id поле (blog_id в данном случае) или связанному полю (blog__pk) для обеспечения соответствия обоих выражений.
values()
-
values(*fields, **expressions)
Возвращает QuerySet , возвращающий словари, а не экземпляры модели, при использовании в качестве итерируемого объекта.
Каждый из этих словарей представляет объект, ключи которого соответствуют именам атрибутов объектов модели.
В этом примере сравниваются словари values() с обычными объектами модели:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Метод values() принимает необязательные позиционные аргументы, *fields, которые указывают имена полей, до которых должна быть ограничена SELECT. Если вы укажите поля, каждый словарь будет содержать только ключи/значения полей, которые вы указали. Если вы не укажете поля, каждый словарь будет содержать ключ и значение для каждого поля в таблице базы данных.
Пример:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Метод values() также принимает необязательные именованные аргументы, **expressions, которые передаются методу annotate():
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
Вы можете использовать встроенные и пользовательские функции сортировки. Например:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values('name__lower')
<QuerySet [{'name__lower': 'beatles blog'}]>
Добавлена поддержка функций.
Агрегация внутри values() применяется до других аргументов внутри той же values() строки. Если вам нужно сгруппировать по другому значению, добавьте его в более раннюю values() строку. Например:
>>> from django.db.models import Count
>>> Blog.objects.values('entry__authors', entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values('entry__authors').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
Некоторые нюансы, которые стоит отметить:
-
Если у вас есть поле с именем
foo, которое являетсяForeignKey, вызовvalues()по умолчанию вернёт словарь с ключомfoo_id, так как это имя скрытого атрибута модели, хранящего фактическое значение (атрибутfooотносится к связанной модели). При вызовеvalues()и передаче имён полей, вы можете передать какfoo, так иfoo_id, и получите то же самое (ключ словаря будет соответствовать имени поля, которое вы передали).Например:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values('blog') <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values('blog_id') <QuerySet [{'blog_id': 1}, ...]> - При использовании
values()вместе сdistinct(), имейте в виду, что сортировка может повлиять на результаты. См. примечание вdistinct()для получения подробностей. - Если вы используете
values()строку после вызоваextra(), любые поля, определённые аргументомselectв вызовеextra(), должны быть явно включены в вызовvalues(). Любой вызовextra(), сделанный после вызоваvalues(), проигнорирует дополнительные выбранные поля. - Вызов
only()иdefer()послеvalues()не имеет смысла, поэтому это приведёт к исключениюNotImplementedError. -
Объединение преобразований и агрегатов требует использования двух вызовов
annotate(), явно или в качестве аргументов кvalues(). Как и выше, если преобразование зарегистрировано в соответствующем типе поля, первый вызовannotate()можно опустить, поэтому следующие примеры эквивалентны:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values( ... entry__authors__name__lower=Lower('entry__authors__name') ... ).annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate( ... entry__authors__name__lower=Lower('entry__authors__name') ... ).values('entry__authors__name__lower').annotate(entries=Count('entry')) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
Это полезно, когда вы знаете, что вам понадобятся только значения из небольшого количества доступных полей и вам не потребуется функциональность объекта модели. Более эффективно выбрать только необходимые поля.
Наконец, обратите внимание, что вы можете вызвать filter(), order_by(), и т.д. после вызова values(), что означает, что эти два вызова идентичны:
Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()
Создатели Django предпочитают, чтобы все методы, влияющие на SQL, стояли первыми, за которыми (необязательно) следуют методы, влияющие на вывод (такие как values()), но это не принципиально. Это ваш шанс продемонстрировать индивидуальность.
Вы также можете ссылаться на поля связанных моделей с обратными отношениями через атрибуты OneToOneField, ForeignKey и ManyToManyField:
>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Предупреждение
Так как атрибуты ManyToManyField и обратные отношения могут иметь несколько связанных строк, включение этих полей может увеличить размер набора результатов. Это будет особенно заметно, если вы включите несколько таких полей в ваш запрос values(), в этом случае будут возвращены все возможные комбинации.
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,)]>
Добавлен параметр named.
dates()
-
dates(field, kind, order='ASC')
Возвращает QuerySet , который вычисляется в список объектов datetime.date, представляющих все доступные даты определённого типа в содержимом QuerySet.
field должно быть именем DateField вашей модели. kind должно быть "year", "month", "week", или "day". Каждый объект datetime.date в списке результатов «обрезан» до заданного type.
-
"year"возвращает список всех уникальных значений года для поля. -
"month"возвращает список всех уникальных значений год/месяц для поля. -
"week"возвращает список всех уникальных значений год/неделя для поля. Все даты будут понедельниками. -
"day"возвращает список всех уникальных значений год/месяц/день для поля.
order, по умолчанию 'ASC', должно быть либо 'ASC', либо 'DESC'. Это определяет, как упорядочить результаты.
Примеры:
>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'week')
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]
Добавлена поддержка «недели».
datetimes()
-
datetimes(field_name, kind, order='ASC', tzinfo=None)
Возвращает QuerySet, который вычисляется в список datetime.datetime объектов, представляющих все доступные даты определенного типа в содержимом QuerySet.
field_name должно быть именем DateTimeField вашей модели.
kind должно быть либо "year", "month", "week", "day", "hour", "minute", или "second". Каждый объект datetime.datetime в списке результатов «обрезан» до указанного type.
order, по умолчанию 'ASC', должно быть либо 'ASC' или 'DESC'. Это определяет порядок сортировки результатов.
tzinfo определяет часовой пояс, в который преобразуются даты и время перед обрезкой. Действительно, заданная дата и время имеют разные представления в зависимости от используемого часового пояса. Этот параметр должен быть объектом datetime.tzinfo. Если это None, Django использует текущий часовой пояс. Он не оказывает никакого влияния, когда USE_TZ имеет значение False.
Добавлена поддержка «недели».
Примечание
Эта функция выполняет преобразования часовых поясов непосредственно в базе данных. Вследствие этого ваша база данных должна уметь интерпретировать значение 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()
Возвращает копию текущего набора запросов (или подкласса набора запросов). Это может быть полезно в ситуациях, когда вы хотите передать либо менеджер модели, либо набор запросов и выполнить дополнительную фильтрацию результата. После вызова all() для любого из объектов у вас обязательно будет набор запросов для работы.
Когда набор запросов 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 в объединённых запросах.
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()),
)
и выполните:
>>> Pizza.objects.all() ["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
Проблема в том, что каждый раз, когда Pizza.__str__() запрашивает self.toppings.all(), ему необходимо выполнить запрос к базе данных, поэтому Pizza.objects.all() выполнит запрос к таблице Toppings для каждого элемента в таблице Pizza 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')
Это предварительно загрузит все пиццы, принадлежащие ресторанам, и все заливные элементы, относящиеся к этим пиццам. Это приведет к общему количеству запросов в базу данных: одному для ресторанов, одному для пицц и одному для заливных элементов.
>>> 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. Если вам нужно его использовать, пожалуйста, отправьте запрос с помощью ключа QuerySet.extra со своим случаем использования (сначала проверьте список существующих запросов), чтобы мы могли улучшить API QuerySet для удаления extra(). Мы больше не улучшаем и не исправляем ошибки для этого метода.
Например, это использование extra():
>>> qs.extra(
... select={'val': "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
эквивалентно:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
Основное преимущество использования RawSQL заключается в том, что вы можете установить output_field при необходимости. Основной недостаток заключается в том, что если вы ссылаетесь на какой-либо псевдоним таблицы queryset в сыром SQL, то Django может изменить этот псевдоним (например, когда queryset используется в качестве подзапроса в ещё одном запросе).
Предупреждение
Вы должны быть очень осторожны всякий раз, когда используете extra(). Каждый раз, когда вы используете его, вы должны экранировать любые параметры, которые пользователь может контролировать, используя params, чтобы защититься от атак SQL-инъекции.
Также не нужно заключать в кавычки плейсхолдеры в строке SQL. Этот пример уязвим для SQL-инъекции из-за кавычек вокруг %s:
"select col from sometable where othercol = '%s'" # unsafe!
Вы можете узнать больше о том, как работает защита Django от SQL-инъекций.
По определению, эти дополнительные поиски могут быть не переносимы на различные движки баз данных (поскольку вы явно пишете код SQL) и нарушают принцип DRY, поэтому вы должны избегать их, если это возможно.
Укажите один или несколько из params, select, where или tables. Ни один из аргументов не является обязательным, но вы должны использовать хотя бы один из них.
-
selectАргумент
selectпозволяет поместить дополнительные поля вSELECT-оператор. Он должен быть словарем, сопоставляющим имена атрибутов с SQL-оператор, используемым для вычисления этого атрибута.Пример:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})В результате каждый объект
Entryбудет иметь дополнительный атрибут,is_recent, булево значение, представляющее, является ли записьpub_dateбольше 1 января 2006 года.Django вставляет заданный фрагмент SQL непосредственно в
SELECTоператор, поэтому результирующий SQL в приведенном выше примере будет примерно таким:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Следующий пример более сложный; он выполняет подзапрос, чтобы дать каждому результирующему объекту
Blogатрибутentry_count, целое число, представляющее количество связанных объектовEntry:Blog.objects.extra( select={ 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' }, )В этом конкретном случае мы используем тот факт, что запрос уже будет содержать таблицу
blog_blogв еёFROMчасти.Результирующий SQL в приведенном выше примере будет следующим:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Обратите внимание, что круглые скобки, необходимые большинству СУБД вокруг подзапросов, не требуются в
selectоператоре Django. Также обратите внимание, что некоторые базы данных, такие как некоторые версии MySQL, не поддерживают подзапросы.В некоторых редких случаях вы можете захотеть передать параметры фрагментам SQL в
extra(select=...). Для этого используйте параметрselect_params. Посколькуselect_paramsявляется последовательностью, а атрибутselect- словарем, необходимо соблюдать осторожность, чтобы параметры правильно сопоставлялись с дополнительными элементами выборки. В этой ситуации для значенияselectследует использоватьcollections.OrderedDict, а не обычный словарь 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()в начало построения queryset, так чтобы ваша таблица была первым использованием этой таблицы. Наконец, если всё остальное не сработает, посмотрите на созданный запрос и перепишите добавлениеwhereтаким образом, чтобы использовать псевдоним, заданный вашей дополнительной таблице. Псевдоним будет таким же каждый раз, когда вы создаёте queryset таким же образом, поэтому вы можете полагаться на имя псевдонима, чтобы он не изменился. -
order_byЕсли вам нужно отсортировать результирующий queryset, используя некоторые новые поля или таблицы, которые вы включили с помощью
extra(), используйте параметрorder_byдляextra()и передайте последовательность строк. Эти строки должны быть либо полями модели (как в обычном методеorder_by()для queryset), в формате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. Если вы используете результаты queryset в ситуации, где вы не знаете, нужны ли вам эти конкретные поля, когда вы изначально получаете данные, вы можете указать Django, чтобы он не извлекал их из базы данных.
Это делается путем передачи имен полей, которые не должны загружаться, в defer():
Entry.objects.defer("headline", "body")
Queryset, имеющий отложенные поля, по-прежнему вернёт экземпляры моделей. Каждое отложенное поле будет извлечено из базы данных, если вы обратитесь к этому полю (по одному, а не ко всем отложенным полям сразу).
Вы можете выполнить несколько вызовов 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 на поддерживаемых базах данных.
Например:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
При оценке набора запросов (в данном случае for entry in entries) все совпавшие записи будут заблокированы до конца блока транзакций, что означает, что другие транзакции не смогут их изменять или приобретать блокировки на них.
Обычно, если другая транзакция уже приобрела блокировку на одной из выбранных строк, запрос будет блокироваться до тех пор, пока блокировка не будет освобождена. Если это не то поведение, которое вы хотите, вызовите select_for_update(nowait=True). Это сделает вызов без блокировки. Если другая транзакция уже приобрела конкурирующую блокировку, DatabaseError будет поднята при оценке набора запросов. Вы также можете игнорировать заблокированные строки, используя select_for_update(skip_locked=True) вместо этого. nowait и skip_locked взаимоисключают, и попытка вызвать select_for_update() с обоими вариантами включенными приведёт к ValueError.
По умолчанию select_for_update() блокирует все строки, выбранные запросом. Например, строки связанных объектов, указанные в select_related(), блокируются дополнительно к строкам модели набора запросов. Если это нежелательно, укажите связанные объекты, которые вы хотите заблокировать в select_for_update(of=(...)) с использованием того же синтаксиса полей, что и select_related(). Используйте значение 'self' для ссылки на модель набора запросов.
Блокировка родительских моделей в select_for_update(of=(...))
Если вы хотите заблокировать родительские модели при использовании наследования от нескольких таблиц, вы должны указать поля связи родителя (по умолчанию <parent_model_name>_ptr) в аргументе of. Например:
Restaurant.objects.select_for_update(of=('self', 'place_ptr'))
Вы не можете использовать select_for_update() на отношениях, допускающих значения 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
Чтобы обойти это ограничение, вы можете исключить объекты NULL, если вам они не нужны:
>>> 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() в режиме автосохранения на бэкендах, которые поддерживают SELECT ... FOR UPDATE, — ошибка TransactionManagementError, потому что в этом случае строки не блокируются. Если это будет разрешено, это приведет к повреждению данных и может быть легко вызвано кодом, который ожидает выполнения вне транзакции.
Использование select_for_update() на бэкендах, которые не поддерживают SELECT ... FOR UPDATE (например, SQLite), не повлияет. SELECT ... FOR UPDATE не будет добавлен в запрос, и ошибка не будет поднята, если select_for_update() используется в режиме автосохранения.
Предупреждение
Хотя select_for_update() обычно не срабатывает в режиме автосохранения, так как TestCase автоматически оборачивает каждый тест в транзакцию, вызов select_for_update() в TestCase даже за пределами блока atomic() пройдёт (возможно, неожиданно), без подъёма TransactionManagementError. Для правильного тестирования select_for_update() следует использовать TransactionTestCase.
Определённые выражения могут не поддерживаться
PostgreSQL не поддерживает select_for_update() с выражениями Window.
Добавлен аргумент of.
raw()
-
raw(raw_query, params=None, translations=None)
Принимает сырой SQL-запрос, выполняет его и возвращает экземпляр django.db.models.query.RawQuerySet. Этот экземпляр RawQuerySet можно перебирать так же, как обычный экземпляр QuerySet, чтобы получить экземпляры объектов.
Дополнительную информацию см. в разделе Выполнение сырых SQL-запросов.
Предупреждение
raw() всегда запускает новый запрос и не учитывает предыдущие фильтры. Поэтому его следует вызывать в основном из Manager или из нового экземпляра QuerySet.
Операторы, возвращающие новые QuerySet
Объединённые наборы запросов должны использовать одну и ту же модель.
И (&)
Объединяет два QuerySet с помощью оператора SQL AND.
Следующие выражения эквивалентны:
Model.objects.filter(x=1) & Model.objects.filter(y=2) Model.objects.filter(x=1, y=2) from django.db.models import Q Model.objects.filter(Q(x=1) & Q(y=2))
SQL эквивалент:
SELECT ... WHERE x=1 AND y=2
ИЛИ (|)
Объединяет два QuerySet с помощью оператора SQL OR.
Следующие выражения эквивалентны:
Model.objects.filter(x=1) | Model.objects.filter(y=2) from django.db.models import Q Model.objects.filter(Q(x=1) | Q(y=2))
SQL эквивалент:
SELECT ... WHERE x=1 OR y=2
Методы, которые не возвращают 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() с filter() и используя Q objects. Например, чтобы получить Роберта или Боба Марли, если хотя бы один из них существует, и создать последнего в противном случае:
from django.db.models import Q
obj, created = Person.objects.filter(
Q(first_name='Bob') | Q(first_name='Robert'),
).get_or_create(last_name='Marley', defaults={'first_name': 'Bob'})
Если найдено несколько объектов, get_or_create() вызывает MultipleObjectsReturned. Если объект не найден, get_or_create() создаст и сохранит новый объект, вернув кортеж из нового объекта и True. Новый объект будет создан примерно по следующему алгоритму:
params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
Проще говоря, это означает начать с любого ключевого аргумента, не содержащего двойного подчёркивания (что указывает на поиск, не по совпадению значений), а затем добавить содержимое defaults, перезаписывая необходимые ключи, и использовать результат в качестве ключевых аргументов для класса модели. Если в defaults есть вызываемые объекты, оцените их. Как было указано выше, это упрощённый алгоритм, но он содержит все существенные детали. Внутренняя реализация содержит больше проверок на ошибки и обрабатывает дополнительные граничные условия; если вас интересует это, прочтите код.
Если у вас есть поле, названное defaults, и вы хотите использовать его как точный поиск в get_or_create(), просто используйте 'defaults__exact', как показано ниже:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
Метод get_or_create() имеет поведение с ошибками, аналогичное create(), когда вы используете вручную указанные первичные ключи. Если необходимо создать объект, а ключ уже существует в базе данных, будет вызвано исключение IntegrityError.
Этот метод атомен при условии корректного использования, правильной конфигурации базы данных и правильного поведения баз данных. Однако, если уникальность не навязана на уровне базы данных для kwargs используемого в вызове get_or_create (см. unique или unique_together), этот метод уязвим для гонки, что может привести к одновременной вставке нескольких строк с одинаковыми параметрами.
Если вы используете MySQL, убедитесь, что вы используете уровень изоляции READ COMMITTED, а не REPEATABLE READ (по умолчанию), иначе вы можете столкнуться с ситуациями, когда get_or_create вызывает исключение IntegrityError, но объект не появится в последующем вызове get().
Наконец, несколько слов об использовании get_or_create() в представлениях Django. Пожалуйста, используйте его только в POST запросах, если у вас нет веской причины не делать этого. GET запросы не должны оказывать никакого влияния на данные. Вместо этого используйте POST всякий раз, когда запрос на страницу оказывает побочное действие на ваши данные. Дополнительная информация приведена в разделе Безопасные методы спецификации HTTP.
Предупреждение
Вы можете использовать get_or_create() через атрибуты ManyToManyField и обратные связи. В этом случае вы ограничите запросы в рамках этой связи. Это может привести к проблемам целостности, если вы не используете его последовательно.
Предположим, у вас есть следующие модели:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
Вы можете использовать get_or_create() через поле главы книги, но это только извлекает данные в контексте этой книги:
>>> book = Book.objects.create(title="Ulysses") >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, True) >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, False) >>> Chapter.objects.create(title="Chapter 1") <Chapter: Chapter 1> >>> book.chapters.get_or_create(title="Chapter 1") # Raises IntegrityError
Это происходит потому, что он пытается получить или создать «Главу 1» в книге «Улисс», но не может сделать ни того, ни другого: связь не может получить доступ к этой главе, потому что она не связана с этой книгой, и не может создать её, потому что поле title должно быть уникальным.
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.
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.
Пример:
# 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) по результатам. Набор запросов обычно кэширует свои результаты внутри себя, чтобы повторные оценки не приводили к дополнительным запросам. В отличие от этого, QuerySet будет читать результаты напрямую без кэширования на уровне 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:
Добавлен параметр 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() могут возвращать экземпляры с датами NULL.
Поскольку сортировка делегируется базе данных, результаты по полям, допускающим значения NULL, могут сортироваться по-разному при использовании разных баз данных. Например, PostgreSQL и MySQL сортируют значения NULL так, как будто они больше, чем значения не NULL, в то время как SQLite делает наоборот.
Возможно, вы захотите отфильтровать значения NULL:
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})
По умолчанию Django’s ForeignKey эмулирует SQL ограничение ON DELETE CASCADE — другими словами, все объекты с внешними ключами, указывающими на объекты, которые будут удалены, будут удалены вместе с ними. Например:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'weblog.Blog': 1, 'weblog.Entry': 2, 'weblog.Entry_authors': 2})
Это поведение каскадирования настраивается с помощью аргумента on_delete к ForeignKey.
Метод delete() выполняет массовое удаление и не вызывает никаких delete() методов ваших моделей. Однако он генерирует сигналы pre_delete и post_delete для всех удаленных объектов (включая каскадные удаления).
Django нужно загрузить объекты в память, чтобы отправлять сигналы и обрабатывать каскады. Однако, если нет каскадов и нет сигналов, Django может использовать быстрый путь и удалять объекты без загрузки в память. Для больших удалений это может значительно уменьшить использование памяти. Также может быть уменьшено количество выполненных запросов.
Внешние ключи, установленные на on_delete DO_NOTHING не препятствуют использованию быстрого пути при удалении.
Обратите внимание, что запросы, сгенерированные при удалении объектов, являются реализационным деталями, которые могут быть изменены.
as_manager()
-
classmethod as_manager()
Метод класса, который возвращает экземпляр Manager с копией методов QuerySet. См. Создание менеджера с методами QuerySet для получения более подробной информации.
explain()
-
explain(format=None, **options)
Возвращает строку плана выполнения QuerySet, в которой подробно описывается, как база данных выполнит запрос, включая используемые индексы или объединения. Знание этих деталей может помочь улучшить производительность медленных запросов.
Например, при использовании PostgreSQL:
>>> print(Blog.objects.filter(title='My Blog').explain()) Seq Scan on blog (cost=0.00..35.50 rows=10 width=12) Filter: (title = 'My Blog'::bpchar)
Вывод существенно различается между базами данных.
explain() поддерживается всеми встроенными бэкендами баз данных, кроме Oracle, так как там реализация нетривиальна.
Параметр format изменяет формат вывода с базы данных на стандартный, обычно текстовый. PostgreSQL поддерживает 'TEXT', 'JSON', 'YAML', и 'XML'. MySQL поддерживает 'TEXT' (также называемый 'TRADITIONAL') и 'JSON'.
Некоторые базы данных принимают флаги, которые могут вернуть больше информации о запросе. Передайте эти флаги в качестве ключевых аргументов. Например, при использовании PostgreSQL:
END_OF_DOCUMENT_MARKER>>> print(Blog.objects.filter(title='My Blog').explain(verbose=True)) Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1) Output: id, title Filter: (blog.title = 'My Blog'::bpchar) Planning time: 0.064 ms Execution time: 0.058 ms
На некоторых базах данных флаги могут привести к выполнению запроса, что может оказать неблагоприятное влияние на вашу базу данных. Например, флаг ANALYZE PostgreSQL может привести к изменениям данных, если существуют триггеры или если вызывается функция, даже для запроса SELECT.
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]) Entry.objects.filter(headline__in='abc')
Эквиваленты в SQL:
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
Также можно использовать набор результатов запроса для динамической оценки списка значений вместо предоставления списка литеральных значений:
inner_qs = Blog.objects.filter(name__contains='Cheddar') entries = Entry.objects.filter(blog__in=inner_qs)
Этот набор результатов запроса будет обработан как подзапрос:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Если вы передаете QuerySet, полученный из values() или values_list(), в качестве значения для поиска __in, необходимо убедиться, что в результате извлекается только одно поле. Например, это сработает (фильтрация по названиям блогов):
inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)
Этот пример вызовет исключение, так как внутренний запрос пытается извлечь два значения поля, тогда как ожидается только одно:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)
Учитывая производительность
Будьте осторожны при использовании вложенных запросов и учитывайте характеристики производительности вашего сервера базы данных (если сомневаетесь, проведите тестирование!). Некоторые серверы баз данных, в частности MySQL, не оптимизируют вложенные запросы очень хорошо. В таких случаях более эффективным является извлечение списка значений и затем передача его во второй запрос. То есть, выполните два запроса вместо одного:
values = Blog.objects.filter(
name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Обратите внимание на вызов list() вокруг Blog QuerySet, чтобы принудительно выполнить первый запрос. Без него был бы выполнен вложенный запрос, потому что наборы результатов запросов являются ленивыми.
gt
Больше чем.
Пример:
Entry.objects.filter(id__gt=4)
Эквивалент в SQL:
SELECT ... WHERE id > 4;
gte
Больше или равно.
lt
Меньше чем.
lte
Меньше или равно.
startswith
Чувствительное к регистру начинается с.
Пример:
Entry.objects.filter(headline__startswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite не поддерживает чувствительные к регистру запросы LIKE; startswith ведет себя как istartswith для SQLite.
istartswith
Нечувствительное к регистру начинается с.
Пример:
Entry.objects.filter(headline__istartswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline ILIKE 'Lennon%';
Пользователи SQLite
При использовании SQLite-бекенда и строк, не являющихся ASCII, обратите внимание на примечание к базе данных о сравнении строк.
endswith
Чувствительное к регистру заканчивается на.
Пример:
Entry.objects.filter(headline__endswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline LIKE '%Lennon';
Пользователи SQLite
SQLite не поддерживает чувствительные к регистру запросы LIKE; endswith ведет себя как iendswith для SQLite. Обратитесь к документации примечания к базе данных для получения дополнительной информации.
iendswith
Нечувствительное к регистру заканчивается на.
Пример:
Entry.objects.filter(headline__iendswith='Lennon')
Эквивалент в SQL:
SELECT ... WHERE headline ILIKE '%Lennon'
Пользователи SQLite
При использовании SQLite-бекенда и строк, не являющихся ASCII, обратите внимание на примечание к базе данных о сравнении строк.
range
Проверка диапазона (включая границы).
Пример:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
Эквивалент в SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Можно использовать range везде, где можно использовать BETWEEN в SQL — для дат, чисел и даже символов.
Предупреждение
Фильтрация DateTimeField по датам не будет включать элементы последнего дня, так как границы интерпретируются как «0:00 в указанную дату». Если pub_date был бы DateTimeField, вышеприведённое выражение было бы преобразовано в SQL таким образом:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Как правило, нельзя смешивать даты и даты и время.
date
Для полей 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
Для полей date и 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
Для полей date и 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
Для полей даты и времени, точное совпадение дня. Разрешает цепочку дополнительных поисков полей. Принимает целое число дня.
Пример:
Entry.objects.filter(pub_date__day=3) Entry.objects.filter(pub_date__day__gte=3)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date на третье число месяца, например, 3 января, 3 июля и т.д.
Когда USE_TZ равно True, поля времени и даты преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
week
Для полей даты и времени возвращает номер недели (1-52 или 53) в соответствии со ISO-8601, т.е. недели начинаются с понедельника, а первая неделя содержит первый четверг года.
Пример:
Entry.objects.filter(pub_date__week=52) Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(Для этого поиска не включен эквивалентный фрагмент кода SQL, потому что реализация соответствующего запроса различается у разных движков баз данных.)
Когда USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией.
week_day
Для полей даты и времени совпадение по «дню недели». Разрешает цепочку дополнительных поисков полей.
Принимает целое значение, представляющее день недели от 1 (воскресенье) до 7 (суббота).
Пример:
Entry.objects.filter(pub_date__week_day=2) Entry.objects.filter(pub_date__week_day__gte=2)
(Для этого поиска не включен эквивалентный фрагмент кода SQL, потому что реализация соответствующего запроса различается у разных движков баз данных.)
Обратите внимание, что это будет соответствовать любой записи с pub_date, которая попадает на понедельник (день 2 недели), независимо от месяца или года, в котором это происходит. Дни недели индексируются с днем 1, являющимся воскресеньем, и днем 7, являющимся субботой.
Когда USE_TZ равно True, поля времени и даты преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
quarter
Для полей даты и времени совпадение по «четверти года». Разрешает цепочку дополнительных поисков полей. Принимает целое значение от 1 до 4, представляющее четверть года.
Пример получения записей во второй четверти (с 1 апреля по 30 июня):
Entry.objects.filter(pub_date__quarter=2)
(Для этого поиска не включен эквивалентный фрагмент кода SQL, потому что реализация соответствующего запроса различается у разных движков баз данных.)
Когда USE_TZ равно True, поля времени и даты преобразуются в текущую часовую зону перед фильтрацией. Это требует определения часовых зон в базе данных.
time
Для полей времени и даты преобразует значение в время. Разрешает цепочку дополнительных поисков полей. Принимает значение datetime.time.
Пример:
Entry.objects.filter(pub_date__time=datetime.time(14, 30)) Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(Для этого поиска не включен эквивалентный фрагмент кода SQL, потому что реализация соответствующего запроса различается у разных движков баз данных.)
Когда USE_TZ равно True, поля преобразуются в текущую часовую зону перед фильтрацией.
hour
Для полей времени и даты точное совпадение часа. Разрешает цепочку дополнительных поисков полей. Принимает целое число от 0 до 23.
Пример:
Event.objects.filter(timestamp__hour=23) Event.objects.filter(time__hour=5) Event.objects.filter(timestamp__hour__gte=12)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Для полей времени и даты, когда USE_TZ равно True, значения преобразуются в текущую часовую зону перед фильтрацией.
minute
Для полей времени и даты точное совпадение минуты. Разрешает цепочку дополнительных поисков полей. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__minute=29) Event.objects.filter(time__minute=46) Event.objects.filter(timestamp__minute__gte=29)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Для полей времени и даты, когда USE_TZ равно True, значения преобразуются в текущую часовую зону перед фильтрацией.
second
Для полей времени и даты точное совпадение секунды. Разрешает цепочку дополнительных поисков полей. Принимает целое число от 0 до 59.
Пример:
Event.objects.filter(timestamp__second=31) Event.objects.filter(time__second=2) Event.objects.filter(timestamp__second__gte=31)
Эквивалент SQL:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(Точная синтаксическая конструкция SQL варьируется для каждого движка базы данных.)
Для полей времени и даты, когда USE_TZ равно True, значения преобразуются в текущую часовую зону перед фильтрацией.
isnull
Принимает либо True, либо False, которые соответствуют запросам SQL IS NULL и IS NOT NULL соответственно.
Пример:
Entry.objects.filter(pub_date__isnull=True)
Эквивалент SQL:
SELECT ... WHERE pub_date IS NULL;
regex
Совпадение по регулярному выражению, учитывающее регистр.
Синтаксис регулярных выражений соответствует используемому движку базы данных. В случае SQLite, который не имеет встроенной поддержки регулярных выражений, эта функция предоставляется с помощью пользовательской функции REGEXP (на Python), и синтаксис регулярных выражений, таким образом, соответствует синтаксису модуля re Python.
Пример:
Entry.objects.get(title__regex=r'^(An?|The) +')
Эквиваленты SQL:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Рекомендуется использовать сырые строки (например, r'foo' вместо 'foo') для передачи синтаксиса регулярного выражения.
iregex
Совпадение по регулярному выражению, не учитывающее регистр.
Пример:
Entry.objects.get(title__iregex=r'^(an?|the) +')
Эквиваленты SQL:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Функции агрегирования
Django предоставляет следующие функции агрегирования в модуле django.db.models. Подробности об использовании этих функций агрегирования см. в руководстве по агрегированию. Обратитесь к документации Aggregate, чтобы узнать, как создавать свои агрегаты.
Предупреждение
SQLite не может обрабатывать агрегацию по полям даты/времени из коробки. Это связано с тем, что в SQLite нет встроенных полей даты/времени, и Django в настоящее время эмулирует эти функции с помощью текстового поля. Попытки использовать агрегацию по полям даты/времени в SQLite приведут к ошибке NotImplementedError.
Примечание
Функции агрегирования возвращают None, когда используются с пустым QuerySet. Например, функция агрегирования Sum возвращает None вместо 0, если QuerySet не содержит записей. Исключением является Count, которая возвращает 0, если QuerySet пусто.
Все агрегаты имеют следующие общие параметры:
expressions
Строки, ссылающиеся на поля модели, или выражения запроса.
output_field
Необязательный аргумент, представляющий поле модели возвращаемого значения
Примечание
При объединении нескольких типов полей Django может определить только output_field, если все поля имеют одинаковый тип. В противном случае вы должны указать output_field самостоятельно.
filter
Необязательный Q object, который используется для фильтрации строк, по которым выполняется агрегация.
См. Условную агрегацию и Фильтрацию по аннотациям для примеров использования.
**extra
Ключевые аргументы, которые могут предоставить дополнительный контекст для SQL, сгенерированного агрегатом.
Avg
-
class Avg(expression, output_field=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
[<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.1/ref/models/querysets/