从django中的查询集中获取第一个对象的最快方法?

时间:2011-02-25 23:26:15

标签: python django performance django-models

我经常发现自己想要从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时,这是一个非常耗费内存的事情。

如何只使用一次数据库调用并且不使用异常对象搅拌内存来完成此操作?

9 个答案:

答案 0 :(得分:294)

Django 1.6 (released Nov 2013)引入了convenience methods first()last(),如果查询集未返回任何对象,则会吞下生成的异常并返回None

答案 1 :(得分:133)

正确的答案是

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

可用于:

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

您不希望先将其转换为列表,因为这会强制对所有记录进行完整的数据库调用。只需执行上述操作即可完成第一项操作。您甚至可以使用.order_by来确保获得您想要的第一个。

请务必添加.get(),否则您将获得QuerySet而不是对象。

答案 2 :(得分:49)

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

答案 3 :(得分:29)

现在,在Django 1.9中,您有查询集的first()方法。

YourModel.objects.all().first()

这是一种比.get()[0]更好的方式,因为如果查询集为空,它不会抛出异常,因此,您不需要使用exists() <进行检查/ p>

答案 4 :(得分:7)

如果您打算经常获取第一个元素 - 您可以按此方向扩展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 :(得分:5)

可以是这样的

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

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

答案 6 :(得分:3)

你应该使用django方法,比如exists。它可以让你使用它。

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

答案 7 :(得分:3)

这也可以起作用:

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

如果它为空,则返回一个空列表,否则返回列表中的第一个元素。

答案 8 :(得分:0)

自Django 1.6起,您可以将filter()与first()方法一起使用,如下所示:

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