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

Leo*_*opd 177 python django performance django-models

通常我发现自己想要从Django中的查询集中获取第一个对象,或者None如果没有则返回.有很多方法可以做到这一切都有效.但我想知道哪个是性能最好的.

qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
    return qs[0]
else:
    return None
Run Code Online (Sandbox Code Playgroud)

这会导致两次数据库调用吗?这似乎很浪费.这更快吗?

qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
    return qs[0]
else:
    return None
Run Code Online (Sandbox Code Playgroud)

另一种选择是:

qs = MyModel.objects.filter(blah = blah)
try:
    return qs[0]
except IndexError:
    return None
Run Code Online (Sandbox Code Playgroud)

这会生成一个数据库调用,这很好.但是需要在很多时候创建一个异常对象,当你真正需要的只是一个简单的if-test时,这是一个非常耗费内存的事情.

如何只使用一次数据库调用并且不使用异常对象搅拌内存?

cod*_*k3y 309

Django 1.6(2013年11月发布)介绍了方便方法 first(),如果查询集没有返回任何对象last(),则会吞下生成的异常并返回None.

  • 另外,`first()`和`last()`对查询强制执行`ORDER BY`子句.它会使结果具有确定性,但最有可能减慢查询速度. (12认同)
  • 它不执行 [:1],所以它没有那么快(除非您无论如何都需要评估整个查询集)。 (2认同)

sto*_*ter 139

正确的答案是

Entry.objects.all()[:1].get()
Run Code Online (Sandbox Code Playgroud)

哪个可以用于:

Entry.objects.filter()[:1].get()
Run Code Online (Sandbox Code Playgroud)

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

一定要添加.get()或者你将得到一个QuerySet而不是一个对象.

  • @JamesLin区别在于[:1] .get()引发DoesNotExist,而[0]引发IndexError. (14认同)
  • 你仍然需要将它包装在一个try ...中,除了ObjectDoesNotExist,它就像原来的第三个选项,但有切片. (9认同)

Ign*_*ams 49

r = list(qs[:1])
if r:
  return r[0]
return None
Run Code Online (Sandbox Code Playgroud)

  • This answer is now outdated, take a look at @cod3monk3y answer for Django 1.6+ (14认同)

lev*_*evi 35

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

YourModel.objects.all().first()
Run Code Online (Sandbox Code Playgroud)

这是一种更好的方式,.get()或者[0]因为如果queryset为空,它不会抛出异常,因此,您不需要检查使用exists()


Nik*_*nyh 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)
Run Code Online (Sandbox Code Playgroud)

定义这样的模型:

class MyModel(models.Model):
    objects = ManagerWithFirstQuery()
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

 first_object = MyModel.objects.filter(x=100).first()
Run Code Online (Sandbox Code Playgroud)


Nic*_*vas 7

这也可以工作:

def get_first_element(MyModel):
    my_query = MyModel.objects.all()
    return my_query[:1]
Run Code Online (Sandbox Code Playgroud)

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


Nau*_*riq 5

它可以是这样的

obj = model.objects.filter(id=emp_id)[0]
Run Code Online (Sandbox Code Playgroud)

要么

obj = model.objects.latest('id')
Run Code Online (Sandbox Code Playgroud)