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

2fjabf4q  于 2023-03-20  发布在  Go
关注(0)|答案(9)|浏览(189)

我经常发现自己想从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测试。
我怎样才能只用一次数据库调用,而不用异常对象搅动内存来完成这一任务呢?

sigwle7e

sigwle7e1#

Django 1.6 (released Nov 2013)引入了方便的方法first()last(),如果查询集没有返回对象,则它们会吞下产生的异常并返回None

vpfxa7rd

vpfxa7rd2#

可以使用数组切片:

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

可与.filter()一起使用:

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

你不想先把它变成一个列表,因为这会强制调用所有记录的完整数据库。只要做上面的操作,它只会拉取第一个。你甚至可以使用.order_by()来确保你得到你想要的第一个。
确保添加.get(),否则您将得到一个QuerySet,而不是一个对象。

9gm1akwq

9gm1akwq3#

现在,在Django1.9中你有first()方法来处理查询集。

YourModel.objects.all().first()

这是比.get()[0]更好的方法,因为如果queryset为空,它不会抛出异常。因此,您不需要使用exists()进行检查

dbf7pr2w

dbf7pr2w4#

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

zengzsys5#

这也可以起作用:

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

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

iih3973s

iih3973s6#

如果您计划经常获取第一个元素-您可以在这个方向上扩展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()
dzjeubhm

dzjeubhm7#

可以这样

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

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

tvokkenx8#

你应该使用django的方法,比如exists,它就在那里等着你去使用。

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

jgwigjjp9#

我发现了一些东西,我认为可能会对任何人谁碰到这个页面有帮助。

**当使用prefetch_related()**时,调用.first()实际上会对数据库进行另一次查询(使用一些OFFSETLIMIT子句),而.all()只返回查询集已经预取的数据。

考虑到这一点,当使用prefetch_related从Django的查询集中选取第一项时,我会选择这个方法:

>>> Entry.objects.all()[0]

相关问题