Django - 限制查询结果

时间:2011-07-04 16:32:42

标签: django

我想获取模型的最后10个实例并使用此代码:

 Model.objects.all().order_by('-id')[:10]

首先拿起所有实例然后只拿最后10个实例是真的吗? 有没有更有效的方法?

7 个答案:

答案 0 :(得分:254)

Django查询集很懒惰。这意味着只有在您专门询问结果时,查询才会访问数据库。

因此,在您打印或实际使用查询结果之前,您可以进一步过滤而无需数据库访问。

如下所示,您的代码只执行一个SQL查询,仅获取最后10个项目。

In [19]: import logging                                 
In [20]: l = logging.getLogger('django.db.backends')    
In [21]: l.setLevel(logging.DEBUG)                      
In [22]: l.addHandler(logging.StreamHandler())      
In [23]: User.objects.all().order_by('-id')[:10]          
(0.000) SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" ORDER BY "auth_user"."id" DESC LIMIT 10; args=()
Out[23]: [<User: hamdi>]

答案 1 :(得分:30)

实际上我认为LIMIT 10会发给数据库,因此切片不会发生在Python中,而是发生在数据库中。

有关详细信息,请参阅limiting-querysets

答案 2 :(得分:11)

看起来问题中的解决方案不再适用于Django 1.7并引发错误: &#34;一旦切片被采取后,无法重新排序查询&#34;

根据文档https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets强制Python切片语法的“step”参数评估Query。它的工作原理如下:

Model.objects.all().order_by('-id')[:10:1]

我仍然想知道在SQL或Python切片中是否执行了限制返回的整个结果数组。将巨大的列表检索到应用程序内存是没有用的。

答案 3 :(得分:2)

是。如果要获取有限的对象子集,可以使用以下代码:

示例:

obj=emp.objects.all()[0:10]

开头0是可选的,所以

obj=emp.objects.all()[:10]

上面的代码返回前10个实例。

答案 4 :(得分:1)

作为对其他有用答案的补充和观察,值得注意的是,实际进行切片时,[:10]将返回列表的前10个元素,而不是后10个。

要获取最后10个,您应该改为[-10:](请参阅here)。这将帮助您避免将order_by('-id')-一起使用来反转元素。

答案 5 :(得分:0)

QuerySets 进行切片会返回 list,这意味着如果您愿意:

>>> Model.objects.all().order_by('-id')[:10]

它将返回一个列表,问题是您无法在 QuerySet

上执行进一步的 list 方法

所以如果你想对返回的结果做更多​​的事情,你可以:

>>> limit = 5 # your choice
>>>
>>> m1 = Model.objects.filter(pk__gte=Model.objects.count() - limit) # last five
>>> m2 = Model.objects.filter(pk__lte=limit)  # first five

现在您可以执行更多方法:

# Just for illustration
>>> m2.annotate(Avg("some_integer_column")) # annotate
>>> m2.annotate(Sum("some_integer_column"))
>>> m2.aggregate(Sum("some_integer_column")) # aggregate

通过使用切片符号([])来限制结果,您还可以限制chain QuerySet methods的能力。

如果您非常确定不需要进行任何进一步的查询,那么切片就可以了。

答案 6 :(得分:-15)

这不是实际发生的事情。 Django不会仅获取所需的结果。 Django会加载完整的数据库表(这是一个stup [id要做的事情)并且只返回最后10条记录。

我已经通过在MySQL服务器上运行SHOW FULL PROCESSLIST来确认这一点,并且查询没有LIMIT子句。

如果要开发需要高可扩展性的大型应用程序,Django不是一个好的选择。