Django ORM - objects.filter()与objects.all().filter() - 首选哪一个?

Dr.*_*lch 37 python django django-orm django-queryset django-managers

我经常看到像这样的结构

MyModel.objects.all().filter(...)
Run Code Online (Sandbox Code Playgroud)

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

MyMode.objects.filter(...)
Run Code Online (Sandbox Code Playgroud)

提供相同的结果.

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

摘自"添加额外管理器方法"一章

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

all()经理方法的定义:

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

这似乎有点像我的矛盾.一方面,Django提供了让管理器方法返回任何首选对象类型的自由,另一方面它需要一个QuerySet用于该all()方法.我知道每个经理都有一个get_queryset被调用的方法all().但谁阻止我压倒all()我的自定义经理?虽然我同意这样做是不好的设计.

  • 所以据我所知,该all()方法不保证返回QuerySet.到底是什么MyModel.objects回报?这句话是否要求all()?还是`get_queryset()?

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

  • 您是否曾遇到过那些会以不合需要的方式搞乱这些方法的经理?

git*_*rik 50

正如您在Django源代码中看到的那样,all()管理器上的方法只是委托给:get_queryset()

def all(self):
    return self.get_queryset()
Run Code Online (Sandbox Code Playgroud)

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

例如,如果要迭代所有项目,则无法执行此操作:

for item in MyModel.objects:
    # do something with item
Run Code Online (Sandbox Code Playgroud)

因为你无法迭代管理器.但是,all()返回QuerySet,可以迭代QuerySet:

for item in MyModel.objects.all():
    # do something with item
Run Code Online (Sandbox Code Playgroud)

一般来说,你永远不应该覆盖all().您可以覆盖,get_queryset()但此方法必须返回QuerySet.

如果你使用像filter()或的过滤器方法exclude(),你就已经有了QuerySet,因为这些方法被代理到QuerySet.所以你不必做类似的事情all().filter().


Bog*_*suc 6

  1. MyModel.objects返回管理器实例。all()返回get_query_set()。我认为当你需要所有物品时,一切都在那里。
  2. 我更喜欢,MyModel.objects.filter()因为另一个只是又一个方法调用,如果我进行过滤,我不需要所有对象:)
  3. 这取决于目的。但是,如果它们重写管理器的基本方法,它们将返回相同的结果格式(例如 QuerySet)

  • 所以答案是“objects.filter()”是首选,因为实际上你不想要所有对象时编写“all()”不是Pythonic”。 (4认同)