Часто мне хочется получить первый объект из набора запросов в Django или вернуть его, None
если его нет. Есть много способов сделать это, которые все работают. Но мне интересно, какой из них наиболее производительный.
qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None
Это приводит к двум вызовам базы данных? Это кажется расточительным. Это быстрее?
qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None
Другой вариант будет:
qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None
Это генерирует один вызов базы данных, что хорошо. Но требует создания объекта исключения в большинстве случаев, что требует очень много памяти, когда все, что вам действительно нужно, - это тривиальный if-тест.
Как я могу сделать это с помощью всего одного вызова базы данных и без использования памяти с объектами исключений?
len()
наборы запросов, всегда используйте.count()
.first()
иlast()
удобные методы: docs.djangoproject.com/en/dev/ref/models/querysets/#firstОтветы:
Django 1.6 (выпущен ноябрь 2013) представил удобные методы
first()
иlast()
которые глотают получившееся исключение и возврат ,None
если QuerySet не возвращает объектов.источник
first()
иlast()
обеспечить соблюдениеORDER BY
условия в запросе. Это сделает результаты детерминированными, но, скорее всего, замедлит запрос.Правильный ответ
Который может быть использован в:
Вы не хотели бы сначала превратить его в список, потому что это вызвало бы полный вызов базы данных всех записей. Просто сделайте выше, и он будет тянуть только первым. Вы могли бы даже использовать,
.order_by
чтобы получить первое, что вы хотите.Обязательно добавьте,
.get()
иначе вы получите QuerySet, а не объект.источник
Entry.objects.all()[0]
?источник
LIMIT 1
к запросу, и я не знаю, что вы можете сделать что-то лучше этого. Тем не менее, внутренне__nonzero__
вQuerySet
реализуются какtry: iter(self).next() except StopIteration: return false...
так не избежать исключений.QuerySet.__nonzero__()
никогда не вызывается, посколькуQuerySet
преобразуется в alist
перед проверкой на правильность. Однако могут возникнуть и другие исключения.StopIteration
исключение.__iter__
чтобы получить новый объект итератора и вызывать егоnext
метод, пока неStopIteration
будет брошен. Так что определенно будет где-то исключение;)Теперь в Django 1.9 у вас есть
first()
метод для наборов запросов.Это лучший способ, чем
.get()
или[0]
потому что он не выдает исключение, если набор запросов пуст, поэтому вам не нужно проверять, используяexists()
источник
Если вы планируете часто получать первый элемент - вы можете расширить QuerySet в этом направлении:
Определите модель следующим образом:
И используйте это так:
источник
Это также может сработать:
если он пустой, то возвращает пустой список, в противном случае он возвращает первый элемент в списке.
источник
Может быть так
или
источник
Вы должны использовать методы Django, как существует. Его там для вас, чтобы использовать его.
источник
Начиная с django 1.6, вы можете использовать filter () с методом first () следующим образом:
источник