我想取一个模型的最后10个实例,并有这样的代码:

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

是不是先选取所有实例,然后只选取最后10个实例? 有没有更有效的方法?


当前回答

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>]

其他回答

切片的QuerySets返回一个列表,这意味着如果你喜欢:

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

它将返回一个列表,问题是你不能在列表上执行进一步的QuerySet方法

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

>>> 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

通过使用切片符号([])来限制结果,也可以限制链接QuerySet方法的能力。

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

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>]

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

例子:

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

开始的0是可选的,所以

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

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

实际上,我认为LIMIT 10会被发布到数据库,这样切片就不会在Python中发生,而是在数据库中发生。

有关更多信息,请参阅limits -querysets。

过滤器问题的简单答案

Notification.objects.filter(user=request.user).order_by("-id")[:limit]

只需输入order_by然后[:limit]