Django ORM - objects.filter() vs. objects.all(). Filter() - какой из них предпочтительнее?

Очень часто я вижу конструкции вроде

MyModel.objects.all().filter(...)

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

MyMode.objects.filter(...)

дает тот же результат.

Однако это похоже на сохранение только для Менеджера по умолчанию из-за следующих двух утверждений в документации Django:

Выдержка из главы "Добавление дополнительных методов менеджера"

Метод Custom Manager может возвращать все, что вы хотите. Он не имеет для возврата QuerySet.

Определение метода менеджера all():

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

Это похоже на противоречие со мной. С одной стороны, Django предлагает свободу, позволяющую методу менеджера возвращать все, что угодно, а с другой - для QuerySet для метода all(). Я знаю, что каждый менеджер имеет метод get_queryset, который вызывается all(). Но кто останавливает меня от переопределения all() в моем пользовательском менеджере? Хотя я согласен, что это будет плохой дизайн.

  • Итак, насколько я вижу, метод all() не гарантирует возврат QuerySet. Что именно возвращает MyModel.objects? Вызывает ли этот оператор all()? или `get_queryset()?

  • Вы предпочитаете MyModel.objects.filter(...) или MyModel.objects.all().filter(...). И если да, то почему?

  • Вы когда-нибудь сталкивались с неуклюжими менеджерами, которые могли бы бесполезно использовать эти методы?

Ответы

Ответ 1

Метод all() в менеджере просто делегирует get_queryset(), как вы можете видеть в исходный код Django:

def all(self):
    return self.get_queryset()

Так что это просто способ получить QuerySet от менеджера. Это может быть удобно для обеспечения того, что вы имеете дело с QuerySet, а не с Менеджером, потому что MyModel.objects возвращает Менеджер.

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

for item in MyModel.objects:
    # do something with item

Потому что вы не можете перебирать Менеджер. Однако all() возвращает QuerySet, вы можете перебирать QuerySet:

for item in MyModel.objects.all():
    # do something with item

Как правило, вы никогда не должны перезаписывать all(). Вы можете перезаписать get_queryset(), но этот метод должен вернуть QuerySet.

Если вы используете метод фильтрации, например filter() или exclude(), у вас уже будет QuerySet, потому что эти методы проксируются в QuerySet. Поэтому вам не нужно делать что-то вроде all().filter().

Ответ 2

  • MyModel.objects возвращает экземпляр менеджера. all() return get_query_set(). Я думаю, что все есть, когда вам нужны все объекты.
  • Я предпочитаю MyModel.objects.filter(), потому что другой - это еще один вызов метода, и мне не нужны все объекты, если я фильтрую:)
  • Это зависит от цели. Но если они переопределяют базовый метод менеджера, они возвращают одинаковый формат результата (например, QuerySet)