Django ORM - objects.filter()与objects.all().filter(),哪个更优?

69 投票
3 回答
84092 浏览
提问于 2025-04-18 00:58

我经常看到像这样的代码:

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 个回答

-2

Mymodel.objects.filter(username='abcd') 这个命令会返回一个包含所有符合条件的记录的列表,也就是说,它会找出所有用户名为'abcd'的记录。

Mymodel.objects.get(pk='abcd') 这个命令则是用来获取一条特定的记录,它会根据主键的值来查找,也就是只会返回主键为'abcd'的那一条记录。

6
  1. MyModel.objects 返回的是管理器的实例。all() 则是返回 get_query_set() 的结果。我觉得 all() 是用来获取所有对象的。
  2. 我更喜欢使用 MyModel.objects.filter(),因为另一个方法多了一步调用,如果我已经在过滤数据,那就不需要获取所有对象了 :)
  3. 这要看具体的目的。不过如果他们重写了管理器的基础方法,返回的结果格式是一样的(比如说是一个查询集)。
91

在管理器上调用 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() 这样做。

撰写回答