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

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

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

Ответ 2

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

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

, который можно использовать в:

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

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

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

Ответ 3

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

Ответ 4

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

YourModel.objects.all().first()

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

Ответ 5

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

Ответ 6

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

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

или

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

Model.objects.filter(field_name=some_param).first()