Самый быстрый способ получить первый объект из набора запросов в Django? - PullRequest
170 голосов
/ 26 февраля 2011

Часто мне хочется получить первый объект из набора запросов в 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-тест.

Как я могу сделать это только с одной базой данныхВызов и без сбивания памяти с исключениями объектов?

Ответы [ 9 ]

297 голосов
/ 18 ноября 2013

Django 1.6 (выпущено в ноябре 2013 г.) представил удобные методы first() и last(), которые проглатывают результирующее исключение и возвращают None, если набор запросов не возвращает объектов.

134 голосов
/ 02 марта 2011

Правильный ответ

Entry.objects.all()[:1].get()

Который может использоваться в:

Entry.objects.filter()[:1].get()

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

Обязательно добавьте .get(), иначе вы получите QuerySet, а не объект.

49 голосов
/ 26 февраля 2011
r = list(qs[:1])
if r:
  return r[0]
return None
29 голосов
/ 06 октября 2016

Теперь в Django 1.9 у вас есть метод first() для наборов запросов.

YourModel.objects.all().first()

Это лучший способ, чем .get() или [0], поскольку он не выдает исключение, если набор запросов пустТаким образом, вам не нужно проверять, используя exists()

7 голосов
/ 05 марта 2012

Если вы планируете часто получать первый элемент - вы можете расширить QuerySet в этом направлении:

class FirstQuerySet(models.query.QuerySet):
    def first(self):
        return self[0]


class ManagerWithFirstQuery(models.Manager):
    def get_query_set(self):
        return FirstQuerySet(self.model)

Определите модель следующим образом:

class MyModel(models.Model):
    objects = ManagerWithFirstQuery()

И используйте это так:

 first_object = MyModel.objects.filter(x=100).first()
5 голосов
/ 11 июня 2013

Это может быть так

obj = model.objects.filter(id=emp_id)[0]

или

obj = model.objects.latest('id')
4 голосов
/ 05 мая 2017

Это также может сработать:

def get_first_element(MyModel):
    my_query = MyModel.objects.all()
    return my_query[:1]

, если оно пустое, затем возвращает пустой список, в противном случае возвращается первый элемент внутри списка.

3 голосов
/ 14 сентября 2012

Вы должны использовать методы django, как существует.Его можно использовать.

if qs.exists():
    return qs[0]
return None
0 голосов
/ 01 июля 2019

Начиная с django 1.6, вы можете использовать filter () с методом first () следующим образом:

Model.objects.filter(field_name=some_param).first()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...