Django ORM - objects.filter()与objects.all().filter(),哪个更优?
我经常看到像这样的代码:
MyModel.objects.all().filter(...)
这段代码会返回默认管理器的一个查询集。乍一看,all()
似乎有点多余,因为
MyMode.objects.filter(...)
也能得到相同的结果。
不过,这似乎只对默认管理器是安全的,因为在Django文档中有以下两条说明:
摘自“添加额外管理器方法”章节
自定义管理器方法可以返回你想要的任何东西。它不一定要返回一个查询集。
all()
管理器方法的定义:
all() 返回当前查询集(或查询集子类)的一个副本。 这在你可能想要传入一个模型管理器或查询集,并对结果进行进一步过滤的情况下非常有用。调用 all() 后,你肯定会得到一个可以使用的查询集。
这让我觉得有点矛盾。一方面,Django允许管理器方法返回任何你想要的对象类型,另一方面,它又要求all()
方法返回一个查询集。我知道每个管理器都有一个get_queryset
方法,这个方法是由all()
调用的。但谁能阻止我在自定义管理器中重写all()
呢?虽然我同意这样做会是个糟糕的设计。
所以就我所见,
all()
方法并不能保证返回一个查询集。那么MyModel.objects
到底返回什么呢?这个语句是调用all()
吗?还是调用了get_queryset()
?你更喜欢
MyModel.objects.filter(...)
还是MyModel.objects.all().filter(...)
?如果是的话,为什么?你有没有遇到过那些会以不好的方式干扰这些方法的奇怪管理器?
3 个回答
Mymodel.objects.filter(username='abcd')
这个命令会返回一个包含所有符合条件的记录的列表,也就是说,它会找出所有用户名为'abcd'的记录。
Mymodel.objects.get(pk='abcd')
这个命令则是用来获取一条特定的记录,它会根据主键的值来查找,也就是只会返回主键为'abcd'的那一条记录。
MyModel.objects
返回的是管理器的实例。all()
则是返回get_query_set()
的结果。我觉得all()
是用来获取所有对象的。- 我更喜欢使用
MyModel.objects.filter()
,因为另一个方法多了一步调用,如果我已经在过滤数据,那就不需要获取所有对象了 :) - 这要看具体的目的。不过如果他们重写了管理器的基础方法,返回的结果格式是一样的(比如说是一个查询集)。
在管理器上调用 all()
方法其实就是在调用 get_queryset()
方法,具体可以参考 Django 的源代码。
def all(self):
return self.get_queryset()
所以,这只是一个从管理器获取查询集(QuerySet)的方法。这很方便,因为你可以确保你处理的是一个 查询集,而不是一个 管理器。因为 MyModel.objects
返回的是一个管理器。
举个例子,如果你想遍历所有的项目,你不能这样做:
for item in MyModel.objects:
# this won't work
因为你不能遍历一个管理器。不过,all()
返回的是查询集,你可以遍历查询集:
for item in MyModel.objects.all():
# do someting with item
一般来说,你不应该重写 all()
方法。你可以 重写 get_queryset()
,但这个方法必须返回一个查询集。
如果你使用像 filter()
或 exclude()
这样的过滤方法,你已经得到了查询集,因为这些方法会被代理到查询集上。所以你不需要像 all().filter()
这样做。