Spec-Zone.ru › Django 1.10

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

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

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

Когда QuerySets обрабатываются

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

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

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

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

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

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

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

  • Сериализация/Кэширование. Подробности о процессах, связанных с сериализацией QuerySet, см. в следующем разделе. Важный момент для данного раздела заключается в том, что результаты считываются из базы данных.
  • repr(). QuerySet обрабатывается при вызове repr() на нём. Это сделано для удобства в интерактивном интерпретаторе Python, чтобы вы могли сразу видеть результаты при интерактивном использовании API.
  • len(). QuerySet обрабатывается при вызове len() на нём. Как можно ожидать, возвращает длину списка результатов.

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

  • list(). Принудительная обработка QuerySet путём вызова list() на нём. Например:

    entry_list = list(Entry.objects.all())
    
  • bool(). Проверка QuerySet в контексте булевого значения, таком как использование bool(), or, and или оператора if, заставит выполнить запрос. Если существует хотя бы один результат, QuerySet имеет значение True, иначе False. Например:

    if Entry.objects.filter(headline="Test"):
       print("There is at least one Entry with the headline Test")
    

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

Сериализация QuerySets

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

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

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

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

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

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

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

QuerySet API

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

class QuerySet(model=None, query=None, using=None) [source]

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

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

ordered

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

db

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

Примечание

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

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

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

filter()

filter(**kwargs)

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

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

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

exclude()

exclude(**kwargs)

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

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

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

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

В терминах SQL это равносильно:

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

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

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

В терминах SQL это равносильно:

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

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

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

annotate()

annotate(*args, **kwargs)

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

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

END_OF_DOCUMENT_MARKER

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

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

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

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

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

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

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

order_by()

order_by(*fields)

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

Пример:

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

Результат выше будет отсортирован по pub_date по убыванию, а затем по headline по возрастанию. Минус перед "-pub_date" указывает на убывание порядок. Возрастание подразумевается. Для случайной сортировки используйте "?", как показано ниже:

Entry.objects.order_by('?')

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

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

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

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

Entry.objects.order_by('blog')

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

Entry.objects.order_by('blog__id')

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

Entry.objects.order_by('blog__name')

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

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

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

Примечание

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

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

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

Event.objects.order_by('children__date')

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

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

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

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

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

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

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

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

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

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

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

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

reverse()

reverse()

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

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

my_queryset.reverse()[:5]

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

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

distinct()

distinct(*fields)

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

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

Примечание

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

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

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

Только в PostgreSQL вы можете передавать позиционные аргументы (*fields) для указания имён полей, к которым относится DISTINCT. Это переводится в SQL запрос SELECT DISTINCT ON. Вот в чём разница. Для обычного вызова distinct(), база данных сравнивает каждое поле в каждой строке при определении того, какие строки являются уникальными. Для вызова distinct() с указанием имён полей база данных будет сравнивать только указанные имена полей.

Примечание

При указании имён полей вы обязательно должны указать order_by() в QuerySet, а поля в order_by() должны начинаться с полей в distinct(), в том же порядке.

Например, SELECT DISTINCT ON (a) даёт вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите произвольную строку.

Примеры (те, что после первого, будут работать только в PostgreSQL):

>>> Author.objects.distinct()
[...]

>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]

>>> Entry.objects.order_by('blog').distinct('blog')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]

>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]

Примечание

Обратите внимание, что order_by() использует любой заданный по умолчанию порядок сортировки связанной модели. Возможно, вам придется явно указать сортировку по связи _id или связанному полю, чтобы убедиться, что DISTINCT ON выражения соответствуют тем, что находятся в начале ORDER BY фрагмента. Например, если модель Blog определяет ordering по name:

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

…это не сработает, потому что запрос будет отсортирован по blog__name, что не соответствует DISTINCT ON выражению. Вам необходимо явно указать сортировку по связи _id полю (blog_id в этом случае) или связанному полю (blog__pk) для обеспечения соответствия обоих выражений.

values()

values(*fields)

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

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

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

    Например:

    >>> Entry.objects.values()
    <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
    
    >>> Entry.objects.values('blog')
    <QuerySet [{'blog': 1}, ...]>
    
    >>> Entry.objects.values('blog_id')
    <QuerySet [{'blog_id': 1}, ...]>
    
  • При использовании values() вместе с distinct(), учтите, что порядок сортировки может повлиять на результаты. См. примечание в distinct() для получения подробностей.
  • Если вы используете values() фрагмент после вызова extra(), любые поля, определённые аргументом select в вызове extra(), должны быть явно включены в вызов values() . Любой вызов extra(), произведённый после вызова values() , проигнорирует дополнительные выбранные поля.
  • Вызов only() и defer() после values() не имеет смысла, поэтому такое действие вызовет NotImplementedError.

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

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

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

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

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

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

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

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

values_list()

values_list(*fields, flat=False)

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

>>> Entry.objects.values_list('id', 'headline')
[(1, 'First entry'), ...]

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

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

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

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

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

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

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

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

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

>>> Author.objects.values_list('name', 'entry__headline')
[('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 для заголовка записи.

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

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

dates()

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

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

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

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

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

Примеры:

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

datetimes()

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

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

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

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

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

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

Примечание

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

  • SQLite: установите pytz — преобразования фактически выполняются в Python.
  • PostgreSQL: нет требований (см. Часовые пояса).
  • Oracle: нет требований (см. Выбор файла часового пояса).
  • MySQL: установите pytz и загрузите таблицы часовых поясов с помощью mysql_tzinfo_to_sql.

none()

none()

Вызов none() создаст запрос, который никогда не вернёт объекты, и при обращении к результатам запрос не будет выполнен. Объект qs.none() является экземпляром EmptyQuerySet.

Примеры:

>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True

all()

all()

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

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

select_related()

select_related(*fields)

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

Следующие примеры иллюстрируют разницу между обычными и 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:

b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.

b = Book.objects.get(id=4) # No select_related() in this example.
p = b.author         # Hits the database.
c = p.hometown       # Hits the database.

Вы можете ссылаться на любое ForeignKey или OneToOneField отношение в списке полей, переданных в select_related().

Вы также можете обратиться к обратному направлению OneToOneField в списке полей, переданных в select_related — то есть вы можете пройти по OneToOneField обратно к объекту, в котором определено поле. Вместо указания имени поля используйте related_name для поля в связанном объекте.

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

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

>>> without_relations = queryset.select_related(None)

Цепочечные вызовы select_related работают аналогично другим методам — то есть select_related('foo', 'bar') эквивалентно select_related('foo').select_related('bar').

prefetch_related()

prefetch_related(*lookups)

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

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

select_related работает путём создания SQL-соединения и включения полей связанного объекта в оператор SELECT . По этой причине select_related получает связанные объекты в одном запросе к базе данных. Однако, чтобы избежать гораздо большего набора результатов, который получился бы при объединении через отношение «многие», select_related ограничен однозначными отношениями — внешним ключом и один-к-одному.

prefetch_related, с другой стороны, выполняет отдельный поиск для каждого отношения и выполняет «объединение» в Python. Это позволяет ему предварительно извлекать объекты «многие-ко-многим» и «многие-к-одному», что невозможно сделать с помощью select_related, в дополнение к отношениям внешнего ключа и один-к-одному, поддерживаемым select_related. Он также поддерживает предварительное извлечение GenericRelation и GenericForeignKey, однако он должен быть ограничен однородным набором результатов. Например, предварительное извлечение объектов, на которые ссылается GenericForeignKey, поддерживается только в том случае, если запрос ограничен одним ContentType.

Например, предположим, что у вас есть эти модели:

from django.db import models

class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

    def __str__(self):              # __unicode__ on Python 2
        return "%s (%s)" % (
            self.name,
            ", ".join(topping.name for topping in self.toppings.all()),
        )

и вы выполняете:

>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...

Проблема в том, что каждый раз, когда Pizza.__str__() запрашивает self.toppings.all(), он должен выполнить запрос к базе данных, поэтому Pizza.objects.all() выполнит запрос к таблице Toppings для каждого элемента в пицце 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() — это новый и другой запрос. Кеш предварительного извлечения здесь не поможет; на самом деле это ухудшает производительность, так как вы выполнили запрос к базе данных, который не использовали. Поэтому используйте эту функцию с осторожностью!

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

class Restaurant(models.Model):
    pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
    best_pizza = models.ForeignKey(Pizza, related_name='championed_by')

Все следующие варианты корректны:

>>> Restaurant.objects.prefetch_related('pizzas__toppings')

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

>>> Restaurant.objects.prefetch_related('best_pizza__toppings')

Это извлечёт лучшую пиццу и все дополнения для лучшей пиццы для каждого ресторана. Это будет выполнено в трёх запросах к базе данных: одном для ресторанов, одном для «лучших пицц» и одном для дополнений.

Конечно, отношение best_pizza также можно извлечь с помощью select_related , чтобы уменьшить количество запросов до двух:

>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')

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

Цепочечные вызовы prefetch_related будут накапливать запросы, которые предварительно извлекаются. Чтобы очистить любое поведение prefetch_related, передайте None в качестве параметра:

>>> non_prefetched = qs.prefetch_related(None)

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

Хотя prefetch_related поддерживает предварительную загрузку GenericForeignKey отношений, количество запросов будет зависеть от данных. Поскольку GenericForeignKey может ссылаться на данные в нескольких таблицах, требуется по одному запросу на каждую ссылающуюся таблицу, а не один запрос на все элементы. Возможно, появятся дополнительные запросы к таблице ContentType, если соответствующие строки еще не были получены.

prefetch_related в большинстве случаев будет реализовано с помощью SQL-запроса, использующего оператор «IN». Это означает, что для большого QuerySet может быть сгенерирована большая строка «IN», что, в зависимости от базы данных, может иметь собственные проблемы с производительностью при парсинге или выполнении SQL-запроса. Всегда проводите профилирование для вашего случая использования!

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

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

В своем простом виде Prefetch эквивалентен традиционному поиску на основе строк:

>>> from django.db.models import Prefetch
>>> Restaurant.objects.prefetch_related(Prefetch('pizzas__toppings'))

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

>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas__toppings', queryset=Toppings.objects.order_by('name')))

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

>>> Pizza.objects.prefetch_related(
...     Prefetch('restaurants', queryset=Restaurant.objects.select_related('best_pizza')))

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

Это позволяет предварительно загрузить то же отношение несколько раз с разным QuerySet; например:

>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', to_attr='menu'),
...     Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'))

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

>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', queryset=vegetarian_pizzas, to_attr='vegetarian_menu'),
...     'vegetarian_menu__toppings')

Использование to_attr рекомендуется при фильтрации результата предварительной загрузки, так как это менее неоднозначно, чем хранение отфильтрованного результата в кэше связанного менеджера:

>>> queryset = Pizza.objects.filter(vegetarian=True)
>>>
>>> # Recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', queryset=queryset, to_attr='vegetarian_pizzas'))
>>> vegetarian_pizzas = restaurants[0].vegetarian_pizzas
>>>
>>> # Not recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
...     Prefetch('pizzas', queryset=queryset))
>>> vegetarian_pizzas = restaurants[0].pizzas.all()

Пользовательская предварительная загрузка также работает с отдельными связанными отношениями, такими как прямые ForeignKey или OneToOneField. Обычно для этих отношений вы захотите использовать select_related(), но есть ряд случаев, когда предварительная загрузка с пользовательским QuerySet полезна:

  • Вы хотите использовать QuerySet, который выполняет дальнейшую предварительную загрузку связанных моделей.
  • Вы хотите предварительно загрузить только подмножество связанных объектов.
  • Вы хотите использовать методы оптимизации производительности, такие как deferred fields:

    >>> queryset = Pizza.objects.only('name')
    >>>
    >>> restaurants = Restaurant.objects.prefetch_related(
    ...     Prefetch('best_pizza', queryset=queryset))
    

Примечание

Порядок поисков имеет значение.

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

>>> prefetch_related('pizzas__toppings', 'pizzas')

Это работает, даже если он неупорядочен, потому что 'pizzas__toppings' уже содержит всю необходимую информацию, поэтому второй аргумент 'pizzas' фактически избыточен.

>>> prefetch_related('pizzas__toppings', Prefetch('pizzas', queryset=Pizza.objects.all()))

Это вызовет ValueError, из-за попытки переопределить набор запросов ранее увиденного поиска. Обратите внимание, что неявный набор запросов был создан для обхода 'pizzas' как части поиска 'pizzas__toppings'.

>>> prefetch_related('pizza_list__toppings', Prefetch('pizzas', to_attr='pizza_list'))

Это вызовет AttributeError, потому что 'pizza_list' еще не существует, когда обрабатывается 'pizza_list__toppings'.

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

extra()

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

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

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

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

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

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

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

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

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

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

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

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

    Также обратите внимание, что некоторые базы данных, такие как некоторые версии MySQL, не поддерживают подзапросы.

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

    Например, это будет работать:

    Blog.objects.extra(
        select=OrderedDict([('a', '%s'), ('b', '%s')]),
        select_params=('one', 'two'))
    

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

  • where / tables

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

    where и tables оба принимают список строк.

    Все параметры where объединяются с другими критериями поиска оператором “И”.

    Пример:

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

    … примерно соответствует следующему SQL-запросу:

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

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

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

  • order_by

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

    Например:

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

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

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

  • params

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

    Пример:

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

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

    Плохой пример:

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

    Хороший пример:

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

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

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

defer()

defer(*fields)

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

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

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

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

Вы можете многократно вызывать defer().

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

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

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

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

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

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

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

Примечание

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

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

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

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

    class Meta:
        managed = False
        db_table = 'app_largetable'

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

    class Meta:
        db_table = 'app_largetable'

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

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

Примечание

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

only()

only(*fields)

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

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

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

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

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

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

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

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

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

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

Примечание

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

using()

using(alias)

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

Например:

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

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

select_for_update()

select_for_update(nowait=False)

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

Например:

entries = Entry.objects.select_for_update().filter(author=request.user)

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

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

В настоящее время postgresql, oracle, и mysql бэкэнды баз данных поддерживают select_for_update(). Однако MySQL не поддерживает аргумент nowait. Очевидно, пользователи внешних сторонних бэкэндов должны проверить документацию своего бэкэнда для получения конкретной информации в этих случаях.

Передача nowait=True в select_for_update() с помощью бэкэндов баз данных, которые не поддерживают nowait, таких как MySQL, приведёт к ошибке DatabaseError. Это сделано для предотвращения непредвиденной блокировки кода.

Оценивание набора запросов с select_for_update() в режиме autocommit на бэкэндах, которые поддерживают 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.

raw()

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

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

Дополнительную информацию см. в разделе Выполнение SQL-запросов.

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

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

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

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

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

get()

get(**kwargs)

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

get() вызывает исключение MultipleObjectsReturned, если найдено более одного объекта. Исключение MultipleObjectsReturned является атрибутом класса модели.

get() вызывает исключение DoesNotExist, если объект не был найден для заданных параметров. Это исключение является атрибутом класса модели. Пример:

Entry.objects.get(id='foo') # raises Entry.DoesNotExist

Исключение DoesNotExist наследуется от django.core.exceptions.ObjectDoesNotExist, поэтому вы можете обрабатывать несколько исключений DoesNotExist. Пример:

from django.core.exceptions import ObjectDoesNotExist
try:
    e = Entry.objects.get(id=3)
    b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
    print("Either the entry or blog doesn't exist.")

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

entry = Entry.objects.filter(...).exclude(...).get()

create()

create(**kwargs)

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

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

и:

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

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

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

get_or_create()

get_or_create(defaults=None, **kwargs)

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

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

Это предназначено как сокращение громоздкого кода. Например:

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

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

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

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

params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update(defaults)
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 — это словарь пар «(поле, значение)», используемый для обновления объекта.

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

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).
  • Он не работает с множественными связями «многие ко многим».
Изменено в Django 1.9:

Была добавлена поддержка использования bulk_create() с прокси-моделями.

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

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

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

count()

count()

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

Пример:

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

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

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

В зависимости от используемой базы данных (например, PostgreSQL или MySQL), count() может возвращать длинное целое число вместо обычного целого числа Python. Это особенность реализации на нижнем уровне, которая не должна создавать проблем на практике.

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

in_bulk()

in_bulk(id_list=None)

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

Пример:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}

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

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

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

iterator()

iterator()

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

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

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

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

Некоторые драйверы баз данных Python, такие как psycopg2, выполняют кэширование при использовании курсоров на стороне клиента (созданные с помощью connection.cursor() и используемые Django ORM). Использование iterator() не влияет на кэширование на уровне драйвера базы данных. Чтобы отключить это кэширование, см. курсоры на серверной стороне.

latest()

latest(field_name=None)

Возвращает самый последний объект в таблице по дате, используя поле даты, указанное как field_name.

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

Entry.objects.latest('pub_date')

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

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

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

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

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

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

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

earliest()

earliest(field_name=None)

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

first()

first()

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

Пример:

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 1.9:

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

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

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

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

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

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

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

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

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

as_manager()

classmethod as_manager()

Метод класса, который возвращает экземпляр Manager с копией методов QuerySet. Подробности см. в разделе Создание менеджера с методами QuerySet.

Field поиски

Поиски по полям — это способ указать суть SQL- %%CODE_BLOCK_866%%% клаузы. Они задаются в качестве ключевых аргументов для методов %%CODE_BLOCK_867%%% filter(), exclude() и get().

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

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

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

exact

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

Примеры:

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

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

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

Сравнения в MySQL

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

iexact

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

Пример:

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

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

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

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

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

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

contains

Регистрозависимое содержимое.

Пример:

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

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

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

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

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

SQLite не поддерживает регистрозависимые %%CODE_BLOCK_894%%%-выражения; contains действует как icontains для SQLite. Подробнее см. в примечании к базе данных.

icontains

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

Пример:

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

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

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

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

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

in

В заданном списке.

Пример:

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

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

SELECT ... WHERE id IN (1, 3, 4);

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

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, полученное в результате %%CODE_BLOCK_906%%% или %%CODE_BLOCK_907%%%, как значение в %%CODE_BLOCK_908%%%-поиск, необходимо убедиться, что вы извлекаете только одно поле в результате. Например, это будет работать (фильтрация по названиям блогов):

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))

Обратите внимание на вызов %%CODE_BLOCK_912%%% вокруг Blog %%CODE_BLOCK_913%%%, чтобы принудительно выполнить первый запрос. Без него будет выполнен вложенный запрос, потому что наборы запросов ленивы.

gt

Больше чем.

Пример:

Entry.objects.filter(id__gt=4)

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

SELECT ... WHERE id > 4;

gte

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

lt

Меньше чем.

lte

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

startswith

Регистрозависимое начало с.

Пример:

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

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

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

SQLite не поддерживает регистрозависимые %%CODE_BLOCK_923%%%-выражения; %%CODE_BLOCK_924%%% действует как %%CODE_BLOCK_925%%% для SQLite.

istartswith

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

Пример:

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

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

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

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

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

endswith

Регистрозависимый конец с.

Пример:

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

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

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

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

SQLite не поддерживает регистрозависимые %%CODE_BLOCK_932%%%-выражения; %%CODE_BLOCK_933%%% действует как %%CODE_BLOCK_934%%% для SQLite. См. документацию примечание к базе данных.

iendswith

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

Пример:

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

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

SELECT ... WHERE headline ILIKE '%will'

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

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

range

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

Пример:

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

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

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

Можно использовать range там, где можно использовать BETWEEN в SQL — для дат, чисел и даже символов.

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

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

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

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

date

Добавлена в Django 1.9.

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

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

Разрешена цепочка дополнительных запросов к полям.

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

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

Разрешена цепочка дополнительных запросов к полям.

day

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

Пример:

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

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

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

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

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

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

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

Разрешена цепочка дополнительных запросов к полям.

week_day

Для полей date и datetime, соответствие «дню недели». Разрешает цепочку дополнительных запросов к полям.

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

Пример:

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

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

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

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

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

Разрешена цепочка дополнительных запросов к полям.

hour

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

Пример:

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

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

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

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

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

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

Добавлена поддержка TimeField в SQLite (в других базах данных она поддерживалась с версии 1.7).

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

Разрешена цепочка дополнительных запросов к полям.

minute

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

Пример:

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

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

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

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

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

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

Добавлена поддержка TimeField в SQLite (в других базах данных она поддерживалась с версии 1.7).

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

Разрешена цепочка дополнительных запросов к полям.

second

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

Пример:

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

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

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

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

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

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

Добавлена поддержка TimeField в SQLite (в других базах данных она поддерживалась с версии 1.7).

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

Разрешена цепочка дополнительных запросов к полям.

isnull

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

Пример:

Entry.objects.filter(pub_date__isnull=True)

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

SELECT ... WHERE pub_date IS NULL;

search

Устаревшее с версии 1.10: См. примечания к выпуску 1.10, чтобы узнать, как его заменить.

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

Пример:

Entry.objects.filter(headline__search="+Django -jazz Python")

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

SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);

Обратите внимание, что это доступно только в MySQL и требует прямого изменения базы данных для добавления полнотекстового индекса. По умолчанию Django использует BOOLEAN MODE для полнотекстовых поисков. Дополнительные сведения см. в документации MySQL.

regex

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

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

Пример:

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 не поддерживает агрегирование по полям date/time «из коробки». Это связано с тем, что в SQLite нет собственных полей date/time, и Django в настоящее время эмулирует эти возможности с помощью текстового поля. Попытки использовать агрегирование по полям date/time в SQLite приведут к ошибке NotImplementedError.

Примечание

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

У всех агрегатов есть следующие общие параметры:

expression

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

output_field

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

Примечание

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

**extra

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

Avg

class Avg(expression, output_field=FloatField(), **extra) [source]

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

  • Значение по умолчанию: <field>__avg
  • Тип возвращаемого значения: float (или тип того, что output_field указано)
Изменено в Django 1.9:

Добавлен параметр output_field, чтобы позволить агрегирование по нечисловым столбцам, таким как DurationField.

Count

class Count(expression, distinct=False, **extra) [source]

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

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

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

distinct

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

Max

class Max(expression, output_field=None, **extra) [source]

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

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

Min

class Min(expression, output_field=None, **extra) [source]

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

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

StdDev

class StdDev(expression, sample=False, **extra) [source]

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

  • По умолчанию псевдоним: <field>__stddev
  • Тип возвращаемого значения: float

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

sample

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

SQLite

SQLite не предоставляет StdDev по умолчанию. Реализация доступна в качестве модуля расширения для SQLite. Обратитесь к документации SQlite за инструкциями по получению и установке этого расширения.

Sum

class Sum(expression, output_field=None, **extra) [source]

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

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

Variance

class Variance(expression, sample=False, **extra) [source]

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

  • По умолчанию псевдоним: <field>__variance
  • Тип возвращаемого значения: float

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

sample

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

SQLite

SQLite не предоставляет Variance по умолчанию. Реализация доступна в качестве модуля расширения для SQLite. Обратитесь к документации SQlite за инструкциями по получению и установке этого расширения.

Инструменты, связанные с запросами

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

Q() объекты

class Q [source]

Объект Q(), подобно объекту F, инкапсулирует SQL-выражение в объекте Python, который может использоваться в операциях, связанных с базой данных.

В общем случае, Q() objects позволяют определять и повторно использовать условия. Это позволяет создавать сложные запросы к базе данных с использованием | (OR) и & (AND) операторов; в частности, иначе невозможно использовать OR в QuerySets.

Prefetch() объекты

class Prefetch(lookup, queryset=None, to_attr=None) [source]

Объект Prefetch() может использоваться для управления работой prefetch_related().

Аргумент lookup описывает отношения для следования и работает так же, как строковые поисковые запросы, переданные prefetch_related(). Например:

>>> from django.db.models import Prefetch
>>> Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch('choice_set')).all()
<QuerySet [<Question: Question object>]>

Аргумент queryset предоставляет базовый QuerySet для данного запроса. Это полезно для дальнейшей фильтрации операции предварительной выборки или для вызова select_related() из предварительно выбранного отношения, тем самым ещё больше уменьшая количество запросов:

>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
<QuerySet [<Choice: The sky>]>
>>> prefetch = Prefetch('choice_set', queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: The sky>]>

Аргумент to_attr устанавливает результат операции предварительной выборки в пользовательское атрибут:

>>> prefetch = Prefetch('choice_set', queryset=voted_choices, to_attr='voted_choices')
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
<QuerySet [<Choice: The sky>]>
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

Примечание

При использовании to_attr предварительно выбранный результат хранится в списке. Это может значительно ускорить работу по сравнению с традиционными вызовами prefetch_related, которые сохраняют кэшированный результат внутри экземпляра QuerySet.

prefetch_related_objects()

prefetch_related_objects(model_instances, *related_lookups) [source]
Добавлено в Django 1.10.

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

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

>>> from django.db.models import prefetch_related_objects
>>> restaurants = fetch_top_restaurants_from_cache()  # A list of Restaurants
>>> prefetch_related_objects(restaurants, 'pizzas__toppings')

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.10/ref/models/querysets/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API