Самый быстрый способ получить первый объект из queryset в django?



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



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

911   8  

8 ответов:

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

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

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

что можно использовать в:

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

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

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

r = list(qs[:1])
if r:
  return r[0]
return None

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

YourModel.objects.all().first()

это лучше, чем .get() или [0] потому что он не выдает исключение, если queryset пуст, поэтому вам не нужно проверять с помощью exists()

Если вы планируете часто получать первый элемент-вы можете расширить 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()

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

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

или

obj = model.objects.latest('id')

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

if qs.exists():
    return qs[0]
return None

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

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

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

Comments

    Ничего не найдено.