Проверка на наличие пустого набора запросов в Django

131

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

orgs = Organisation.objects.filter(name__iexact = 'Fjuk inc')
# If any results
    # Do this with the results without querying again.
# Else, do something else...

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

Теги:
django-queryset

7 ответов

138
Лучший ответ
if not orgs:
    # Do this...
else:
    # Do that...
  • 4
    Это также представляется предпочтительным в документации, например: docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7.
  • 0
    @Wtower Код, на который вы ссылаетесь, должен вызывать контракт 404, если фильтрующее выражение не попадает ни в какие записи, или генерировать list результатов, если есть записи. Код там попадет в базу данных только один раз. Если бы они использовали exist() или count() чтобы сначала проверить, будут ли возвращены записи, они дважды попадут в базу данных (один раз, чтобы проверить, один раз, чтобы получить записи). Это конкретная ситуация. Это не означает, что в общем случае предпочтительным способом узнать, будет ли запрос возвращать записи, является использование do if queryset:...
Показать ещё 3 комментария
156

Начиная с версии 1.2, Django имеет QuerySet. exists() метод, который является наиболее эффективным:

if orgs.exists():
    # Do this...
else:
    # Do that...

Но если вы все равно оцените QuerySet, лучше использовать:

if orgs:
   ...

Для получения дополнительной информации прочитайте документацию QuerySet.exists().

  • 0
    .exists () только для .filter (), есть что-то для .get ()?
15

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

try:
    orgs[0]
    # If you get here, it exists...
except IndexError:
    # Doesn't exist!

В проекте, над которым я работаю с огромной базой данных, not orgs составляет 400+ мс, а orgs.count() - 250 мс. В моих наиболее распространенных случаях использования (те, где есть результаты), этот метод часто получает до менее 20 мс. (Один случай, который я нашел, это было 6.)

Может быть намного длиннее, конечно, в зависимости от того, как далеко должна искать база данных, чтобы найти результат. Или даже быстрее, если он найдет одно быстро; YMMV.

EDIT: это часто будет медленнее, чем orgs.count(), если результат не найден, особенно если условие, на которое вы фильтруете, является редким; в результате, это особенно полезно в функции, где вам нужно убедиться, что существует представление или выбрасывать Http404. (Где, можно надеяться, люди просят URL-адреса, которые существуют чаще, чем нет.)

10

Чтобы проверить пустоту набора запросов:

if orgs.exists():
    # Do something

или вы можете проверить первый элемент в наборе запросов, если он не существует, он вернет None:

if orgs.first():
    # Do something
  • 4
    if orgs.exists() был покрыт ответом, который был предоставлен примерно за 5 лет до этого. Единственное, что этот ответ приносит в таблицу, которая, возможно, является новой, это if orgs.first() . (Даже это спорно: он существенно отличается от делать orgs[0] предложил около 5 лет назад тоже?) Вы должны развивать эту часть ответа: когда бы один хочет сделать это вместо других решений , предложенных ранее?
6

Наиболее эффективным способом (до django 1.2) является следующее:

if orgs.count() == 0:
    # no results
else:
    # alrigh! let continue...
  • 3
    .exists () кажется еще более эффективным
  • 3
    За исключением того, что .exists () был добавлен через несколько месяцев после моего комментария, а Django 1.2 (который включал этот API) был выпущен ~ 8 месяцев спустя. Но спасибо за голосование и не удосужились проверить факты.
Показать ещё 1 комментарий
5

Я не согласен с предикатом

if not orgs:

Это должно быть

if not orgs.count():

У меня была такая же проблема с довольно большим набором результатов (~ 150 тыс. результатов). Оператор не перегружен в QuerySet, поэтому результат фактически распаковывается как список перед проверкой. В моем случае время выполнения сократилось на три порядка.

  • 6
    __nonzero__ уже перегружен в QuerySet. Если результат не кэшируется (он никогда не используется при первом использовании набора запросов), поведение __nonzero__ заключается в переборе всех элементов в наборе запросов. Это очень плохо, если набор большой.
0

Вы также можете использовать это:

if(not(orgs)): #if orgs is empty else: #if orgs is not empty

Ещё вопросы

Сообщество Overcoder
Наверх
Меню