QuerySet API

Этот раздел описывает QuerySet API. Изложенный материал опирается на материал, изложенный в разделах о моделях и выполнении запросов, возможно вам следует прочитать их перед прочтением этого раздела.

В примерах будут использованы :ref:` примеры моделей web-блога <queryset-model-example>` представленные в разделе о выполнении запросов.

Когда вычисляется QuerySets

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

QuerySet будет вычислен при таких действиях:

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

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

    Заметка: не используйте такой подходи, если необходимо всего лишь узнать содержит ли результат запроса хотя бы один объект, и вам не нужен сам результат. Эффективнее использовать метод exists().

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

  • Pickling/кэширование. Смотрите соответствующий раздел о pickling QuerySets. Основное замечание это то, что при этих операциях будет выполнен запрос к базе данных.

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

  • len(). QuerySet будет вычислен при выполнении len() над ним. Как вы и ожидаете будет возвращено количество объектов в результате выборки.

    Заметка: Не используйте len() с QuerySet если вам нужно узнать только количество записей в выборке. Эффективнее использовать подсчет на уровне базы данных, используя оператор SQL SELECT COUNT(*), и Django предоставляет метод count() для этого. Смотрите count() ниже.

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

    entry_list = list(Entry.objects.all())
    

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

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

Если вам необходимо сохранить запрос выполняемый 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, и является частью внутреннего механизма создания запросов. Однако, поддерживает использование pickle и unpickle как показано в примере выше.

You can’t share pickles between versions

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

QuerySet API

Хоть вам и не нужно создавать экземпляр QuerySet самостоятельно — он создается через Manager — вот как это происходит:

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

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

Класс QuerySet имеет два публичных атрибута:

ordered

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

db

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

Примечание

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

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

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

filter

filter(**kwargs)

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

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

exclude

exclude(**kwargs)

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

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

Этот пример исключает все записи с pub_date раньше 3.01.2005 И с 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 раньше 3.01.2005 ИЛИ с headline равным “Hello”:

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

Это эквивалентно запросу SQL:

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

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

annotate

annotate(*args, **kwargs)

“Аннотирует” каждый объект в QuerySet агрегированным значением (среднее, суииа и др.), которое будет вычислено из данных связанных объектов, которые связанны с объектами из``QuerySet``. Аргументы annotate() это “аннотация”, которая будет добавлена для каждого объекта возвращаемого QuerySet.

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

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

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

>>> 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 модели. Вы можете переопределить сортировку используя метод 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 не указан). Например:

Entry.objects.order_by('blog')

...идентично:

Entry.objects.order_by('blog__id')

...т.к. модель Blog не содержит сортировки по-умолчанию.

Будьте осторожны используя по полю из связанной модели и метод distinct(). Смотрите описание метода distinct() для информации как сортировка по связанной модели может повлиять на ожидаемый результат.

Примечание

Можно использовать поля с множеством значений для фильтрации результатов (например, поле ManyToManyField, или обратную связь для поля ForeignKey).

Возьмем такой код:

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

Event.objects.order_by('children__date')

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

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

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

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

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

reverse

reverse()

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

Что бы получить “последние” пять объектов выполните:

my_queryset.reverse()[:5]

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

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

distinct

distinct([*fields])

Возвращает QuerySet с добавленным SELECT DISTINCT в SQL запрос. Повторяющиеся записи будут исключены из результатов запроса.

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

Примечание

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

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

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

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

С Django 1.4, можно передать позиционные аргументы (*fields), указывая какие поля должны использоваться с DISTINCT. Все это будет преобразовано в SELECT DISTINCT ON SQL запрос.

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

Примечание

Возможность указывать поля доступна только в PostgreSQL.

Примечание

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

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

Например:

>>> 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')
[...]

values

values(*fields)

Возвращает ValuesQuerySet — подкласс QuerySet, который возвращает словари с результатом вместо объектов моделей.

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

Этот пример показывает разницу между результатом возвращаемым values() и объектами модели:

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

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

Например:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

Следует упомянуть несколько тонкостей:

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

    Например:

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

  • Используя values() после вызова extra(), добавьте в values() все поля указанные в аргументе select использованном при вызове extra(). При вызове extra() после values() все указанные дополнительные поля будут проигнорированы.

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

Заметим, что ValuesQuerySet подкласс QuerySet, и содержит все методы QuerySet. Вы можете вызвать filter() или order_by(), или любой другой метод. Это означает, что эти два куска кода идентичны:

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

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

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

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

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

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

values_list

values_list(*fields)

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

>>> Entry.objects.values_list('id', 'headline')
[(1, u'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(), будут возвращены все поля модели в порядке, в котором они были объявлены.

dates

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

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

field – название поля модели типа DateField или DateTimeField.

kind должен быть "year", "month" или "day". Каждый объект datetime.datetime - результат “урезания” данных в соответствии с указанным type.

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

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

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

order – сортировка значений. По-умолчанию``’ASC’, должна быть  ``'ASC' или 'DESC'.

Например:

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

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

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

none

none()

Возвращает EmptyQuerySet — подкласс QuerySet который всегда возвращает пустой список. Полезен, если необходимо вернуть пустой результат, но код ожидает объект QuerySet (вместо того, что бы возвращать пустой список, например.)

Например:

>>> Entry.objects.none()
[]

all

all()

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

extra

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

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

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

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

  • select

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

    Например:

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

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

    Django вставит добавленный кусок SQL непосредственно в оператор SELECT, полученный SQL выглядит таким образом:

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

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

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

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

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

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

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

    В некоторых редких случаях, вам понадобится передать параметры в фрагмент SQL из extra(select=...). Для этого, используйте параметр select_params. Так как select_params это последовательность, а атрибут select словарь, необходима некоторая внимательность, что бы параметры корректно были добавлены в оператор SELECT. В этом случае следует использовать a django.utils.datastructures.SortedDict для значения select, вместо обычного словаря Python.

    Например:

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

    Единственное, что нужно помнить используя параметры в extra() – избегать использование "%%s" (тут два знака процента перед s) в параметре select. Django ищет %s и экранированный символ % не будет распознан. Это приведет к неверным результатам.

  • where / tables

    Вы можете добавить оператор SQL WHERE — возможно для выполнения не явного объединения таблиц — by using where. Используя параметр tables можно добавить таблицы в оператор SQL FROM.

    where и tables принимают список строк. Все параметры where будут добавлены к остальным критериям через оператор “AND” .

    Например:

    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 таблиц, которые уже используются запросом. В таком случае Django предполагает, что вы хотите добавить их повторно. Это создает проблему, т.к. таблица будет добавлена с псевдонимом(an alias). Если таблица несколько раз используется в запросе, второй и последующие вхождения должны использовать псевдонимы, что бы база данных могла различить их. При обращении к добавленной таблице в параметре where вы получите ошибку.

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

  • order_by

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

    Например:

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

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

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

  • params

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

    Например:

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

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)
Изменено в Django 1.5.

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

Примечание

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

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

Изменено в Django 1.5.

Примечание

При вызове 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")
Изменено в Django 1.5.

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

Изменено в Django 1.5.

Примечание

При вызове 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)
Добавлено в Django 1.4.

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

Например:

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

Все, удовлетворяющие фильтрам, строки будут заблокированы до завершения транзакции, то есть другие транзакции не смогут изменить или заблокировать это строки.

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

Следует отметить, что использование select_for_update() приводит к тому, что текущая транзакция считается “грязной” (если используется управление транзакциями). Это происходит, потому что Django блокирует указанные записи в БД и держит их до выполнения фиксации(COMMIT) или отката(ROLLBACK) произведённых изменений, освобождая поставленные ранее блокировки в базе данных.

На данный момент, postgresql_psycopg2, oracle, и mysql “бэкэнды” базы данных поддерживают select_for_update(). Однако, MySQL не поддерживает аргумент nowait. Пользователи других баз данных должны уточнить эту информацию в документации используемой базы данных.

Использование nowait=True в select_for_update для базы данных, которая не поддерживает nowait, такой как MySQL, вызовет исключение DatabaseError. Это делается чтобы предотвратить непредвиденную блокировку кода.

Использование select_for_update с базой данных, которая не поддерживает SELECT ... FOR UPDATE (например, SQLite) не будет иметь никакого эфекта.

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

Следующие методы выполняют QuerySet и возвращают не QuerySet.

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

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

create

create(**kwargs)

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

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

и:

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

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

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

get_or_create

get_or_create(**kwargs)

Удобный метод для поиска объекта по заданным параметрам поиска kwargs, и создания нового при необходимости.

Возвращает кортеж (object, created), где 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. Если найдено несколько объектов - будет вызвано исключение MultipleObjectsReturned. Если объект не найден, get_or_create() создаст и сохранит новый объект, возвращая новый объект и True. Новый объект будет создан примерно за таким алгоритмом:

defaults = kwargs.pop('defaults', {})
params = dict([(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.

Этот метод атомарный при правильном использовании, правильной настройке и работе БД. Однако, если уникальность полей не контролируется на уровне БД(unique или unique_together), этот метод сколнен к “гонке-состояний” и в БД могут попасть не уникальные данные(прим. пер. - Django то проверить уникальность, но при нескольких процессах запросы могут одновременно отправиться на выполнения к БД, а там уже ничего не проверяется).

При использовании MySQL, убедитесь что используете READ COMMITTED вместо REPEATABLE READ (по умолчанию), иначе get_or_create может вызывать IntegrityError, но объект не будет возвращен последующим вызовом get().

Наконец, несколько слов об использовании``get_or_create()`` в представлениях Django. Но если вам нужно использовать get_or_create() в представлении, пожалуйста используйте его только для POST запросов, если только у вас нет основательных причин не делать этого. Запросы GET не должны влиять на данные; используйте запрос POST для изменения данных. Подробнее смотрите раздел о безопасных методах в спецификации HTTP.

bulk_create

bulk_create(objs, batch_size=None)
Добавлено в Django 1.4.

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

>>> Entry.objects.bulk_create([
...     Entry(headline="Django 1.0 Released"),
...     Entry(headline="Django 1.1 Announced"),
...     Entry(headline="Breaking: Django is awesome")
... ])

Следует упомянуть ряд оговорок:

  • Метод модели save() не будет вызван, и сигналы pre_save и post_save не будут вызваны.

  • Не работает с дочерними моделями при multi-table наследовании.

  • Если первичный ключ модели это AutoField, его значение не будет получено и атрибут первичного ключа не будет установлен как это делает метод save() .

Параметр 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 vs. MySQL), count() может вернуть long integer вместо обычно целого Python. Это особенности реализации, которые не должны создавать проблем.

in_bulk

in_bulk(id_list)

Получает список первичных ключей и возвращает словарь, ассоциирующий объекты с передаными 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([])
{}

При передаче в in_bulk() пустого списка будет получен пустой словарь.

iterator

iterator()

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

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

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

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

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

latest

latest(field_name=None)

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

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

Entry.objects.latest('pub_date')

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

Как и get(), latest() вызывает исключение DoesNotExist, если объект не найден.

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

aggregate

aggregate(*args, **kwargs)

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

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

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

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

>>> 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_query_set.filter(pk=entry.pk).exists():
    print("Entry contained in queryset")

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

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

И для определения есть ли какой-либо объект в результате:

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

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

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

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

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

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

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

blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
blogs.delete()

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

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

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

Внешние ключи со значением on_delete DO_NOTHING не мешают быстрому удалению.

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

Операторы фильтрации

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

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

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 comparisons

В MySQL, настройка “collation” таблицы базы данных определяет будет ли использовано регистро-зависимое сравнение для exact. Это настройка базы данных, не Django. Можно настроить регистро-зависимое сравнение для таблиц MySQL. Подробности смотрите в разделе о сравнении документации о базах данных.

iexact

Регистро-независимое точное совпадение.

Например:

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

Аналог SQL:

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

Заметим что будет найден 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG' и тд.

SQLite users

Используя SQLite и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite. SQLite не выполняет регистро-независимое сравнение Unicode строк.

contains

Регистро-зависимая проверка на вхождение.

Например:

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

Аналог SQL:

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

Заметим, что будет найдена строка 'Lennon honored today', но не 'lennon honored today'.

SQLite users

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

icontains

Регистро-независимая проверка на вхождение.

Например:

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

Аналог SQL:

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

SQLite users

Используя SQLite и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite.

in

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

Например:

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

Аналог SQL:

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

Вы можете так же передать QuerySet для получения списка значений:

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

Он будет использован как подзапрос:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

Передавая ValuesQuerySet или ValuesListQuerySet (результат вызова values() или values_list()) как аргумент для фильтра __in, вы должны быть уверенным, что результат содержит данные только одного поля. Например, этот код будет работать (фильтр по названиям блога):

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)

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

# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Performance considerations

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

values = Blog.objects.filter(
        name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))

Отметим использование list() с первым QuerySet что бы спровоцировать выполнение запроса. Без этого, он будет использован как подзапрос т.к. QuerySets – ленивы.

gt

Больше чем.

Например:

Entry.objects.filter(id__gt=4)

Аналог SQL:

SELECT ... WHERE id > 4;

gte

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

lt

Меньше чем.

lte

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

startswith

Регистро-зависимая проверка начинается ли поле с указанного значения.

Например:

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

Аналог SQL:

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

SQLite не поддерживает регистро-зависимый оператор LIKE; startswith работает так же как и istartswith для SQLite.

istartswith

Регистро-независимая проверка начинается ли поле с указанного значения.

Например:

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

Аналог SQL:

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

SQLite users

Используя SQLite и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite.

endswith

Регистро-зависимая проверка оканчивается ли поле с указанного значения.

Например:

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

Аналог SQL:

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

SQLite users

SQLite не поддерживает регистро-зависимый оператор LIKE; endswith работает так же как и iendswith для SQLite. Смотрите замечание о сравнении строк в SQLite.

iendswith

Регистро-независимая проверка оканчивается ли поле с указанного значения.

Например:

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

Аналог SQL:

SELECT ... WHERE headline ILIKE '%will'

SQLite users

Используя SQLite и Unicode (не-ASCII) строки, помните замечание о сравнении строк в SQLite.

range

Проверка на вхождение в диапазон (включающий).

Например:

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 по датам не включит записи последнего дня, так как граници интерпретируются как “00:00 указанного дня”. Если pub_date было DateTimeField, мы бы получили следующий SQL запрос:

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

В общем вы не можете использовать date и datetime вместе.

year

Проверка года для полей date/datetime. Принимает значение года из 4-х цифр.

Например:

Entry.objects.filter(pub_date__year=2005)

Аналог SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';

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

month

Проверка месяца для полей date/datetime. Принимает целое число от 1(январь) до 12(декабрь).

Например:

Entry.objects.filter(pub_date__month=12)

Аналог SQL:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';

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

day

Проверка дня месяца для полей date/datetime.

Например:

Entry.objects.filter(pub_date__day=3)

Аналог SQL:

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

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

Заметим, что будут найдены записи, у которых значение pub_date это дата 3-го числа любого месяца, такие как 3-го января, 3-го июля и тд.

week_day

Проверка дня недели для полей date/datetime.

Принимает номер дня недели от 1 (воскресение) до 7 (суббота).

Например:

Entry.objects.filter(pub_date__week_day=2)

(Аналог SQL не представлен т.к. реализация отличается для различных баз данных.)

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

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

Если используются временные зоны , Django использует UTC при подключении к базе данных, это означает что фильтры year, month, day и week_day будут выполнены в UTC. Это ограничение текущей реализации.

isnull

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

Например:

Entry.objects.filter(pub_date__isnull=True)

Аналог SQL:

SELECT ... WHERE pub_date IS NULL;

regex

Регистро-зависимая проверка регулярным выражением.

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

Рекомендуется использовать “raw” строки (например, 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. Подробности, как использовать функции агрегации, смотрите в разделе об агрегации.

Avg

class Avg(field)

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

  • Псевдоним по-умолчанию: <field>__avg

  • Тип возвращаемого значения: float

Count

class Count(field, distinct=False)

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

  • Псевдоним по-умолчанию: <field>__count

  • Тип возвращаемого значения: int

Принимает один не обязательный параметр:

distinct

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

Max

class Max(field)

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

  • Псевдоним по-умолчанию: <field>__max

  • Тип возвращаемого значения: тип указанного поля.

Min

class Min(field)

Возвращает минимальное значение указанного поля.

  • Псевдоним по-умолчанию: <field>__min

  • Тип возвращаемого значения: тип указанного поля.

StdDev

class StdDev(field, sample=False)

Возвращает стандартное отклонение для данных указанного поля.

  • Псевдоним по-умолчанию: <field>__stddev

  • Тип возвращаемого значения: float

Принимает один не обязательный параметр:

sample

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

SQLite

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

Sum

class Sum(field)

Возвращает сумму всех значений указанного поля.

  • Псевдоним по-умолчанию: <field>__sum

  • Тип возвращаемого значения: тип указанного поля.

Variance

class Variance(field, sample=False)

Возвращает дисперсию значений в указанном поле.

  • Псевдоним по-умолчанию: <field>__variance

  • Тип возвращаемого значения: float

Принимает один не обязательный параметр:

sample

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

SQLite

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