56

很多时候我看到像这样的结构

MyModel.objects.all().filter(...)

这将返回默认 Mananger 的 QuerySet。起初all()似乎相当多余,因为

MyMode.objects.filter(...)

提供相同的结果。

但是,这似乎只对默认的 Manager 是安全的,因为 Django 文档中有以下两个语句:

摘自“添加额外的管理器方法”一章

自定义 Manager 方法可以返回您想要的任何内容。它不必返回 QuerySet。

all()管理器方法的定义:

all() 返回当前 QuerySet(或 QuerySet 子类)的副本。这在您可能想要传入模型管理器或 QuerySet 并对结果进行进一步过滤的情况下很有用。在对任一对象调用 all() 之后,您肯定会有一个 QuerySet 可以使用。

这对我来说似乎有点矛盾。一方面,Django 提供了让管理器方法返回任何首选对象类型的自由,另一方面它需要该all()方法的 QuerySet。我知道每个经理都有一个get_querysetall(). 但是谁阻止我all()在我的自定义管理器中覆盖?尽管我同意这样做是不好的设计。

  • 据我所知,该all()方法并不能保证返回一个 QuerySet。究竟MyModel.objects返回什么?这句话叫all()吗?或`get_queryset()?

  • 你喜欢MyModel.objects.filter(...)还是MyModel.objects.all().filter(...)。如果是这样,为什么?

  • 你有没有遇到过不可靠的经理,他们会以一种不受欢迎的方式搞乱这些方法?

4

3 回答 3

76

如您在Django 源代码中所见,管理器上的方法all()只是委托给:get_queryset()

def all(self):
    return self.get_queryset()

所以这只是从Manager获取QuerySet的一种方式。这可以很方便地确保您处理的是QuerySet而不是Manager,因为MyModel.objects它返回一个 Manager。

例如,如果要遍历所有项目,则不能这样做:

for item in MyModel.objects:
    # do something with item

因为您无法迭代 Manager。但是,all()返回 QuerySet,您可以迭代 QuerySet:

for item in MyModel.objects.all():
    # do something with item

通常,您永远不应该覆盖all(). 您可以覆盖get_queryset(),但此方法必须返回一个 QuerySet。

如果您使用类似filter()or的过滤器方法exclude(),那么您已经拥有 QuerySet,因为这些方法被代理到 QuerySet。所以你不必做类似的事情all().filter()

于 2014-04-02T08:56:47.733 回答
3
  1. MyModel.objects返回管理器实例。all()返回get_query_set()。我认为当您需要所有对象时,一切都在那里。
  2. 我更喜欢MyModel.objects.filter()因为另一个只是一个方法调用,如果我过滤,我不需要所有对象:)
  3. 这取决于目的。但是如果它们覆盖了管理器的基本方法,它们会返回相同的结果格式(例如 QuerySet)
于 2014-04-02T07:28:44.427 回答
-2

Mymodel.objects.filter(username='abcd')将给出匹配记录列表 Mymodel.objects.get(pk='abcd') 将返回与主键值匹配的单个记录

于 2019-03-14T03:42:47.233 回答