什么时候应该在 Django 中使用自定义管理器与自定义查询集?

When should I use a custom Manager versus a custom QuerySet in Django?

在 Django 中,自定义管理器是组织可重用查询逻辑的好方法。 Django documentation on Custom managers 表示:

There are two reasons you might want to customize a Manager: to add extra Manager methods, and/or to modify the initial QuerySet the Manager returns.

但是,it goes on to describe 如何自定义 QuerySet 类 也可以创建,并且可以使用 QuerySet.as_manager() 作为管理者直接从数据模型访问这些内容:

The Manager instance created by QuerySet.as_manager() will be virtually identical to the PersonManager from the previous example.

似乎在如何组织自定义 Manager and/or 自定义 QuerySet 类 之间的逻辑方面有很大的灵活性。我应该根据什么原则来决定何时使用其中一种与另一种?

主要是为了便于组合查询。通常,如果您希望能够在查询集调用链中对现有查询集执行某些操作,您可以使用 QuerySet

例如,假设您有一个具有 widthheight 字段的 Image 模型:

class Image(models.Model):
    width = ...  # Width in pixels
    height = ... # Height in pixels

您可以编写一些自定义 QuerySet 方法:

class ImageQuerySet(models.QuerySet): 
    def landscapes(self):
        return self.filter(width__gte=models.F('height'))

    def portraits(self):
        return self.filter(width__lte=models.F('height'))

    def small(self):
        return self.filter(width__lte=1200)

    def large(self):
        return self.filter(width__gte=1200)

class ImageManager(models.Manager):
    def get_queryset(self):
        return ImageQuerySet(self.model, using=self._db)

现在您可以轻松创建动态查询集:

Image.objects.all().portraits().small()
Image.objects.all().large().portraits()

从逻辑上讲,这些函数应该主要关注查询集模型的现有查询集的分区或重新定义。对于不对现有查询集进行操作的情况,您根本不想 return 查询集,或者您可能必须执行一些不涉及此特定模型的相关逻辑,而不是模型管理器它更适合。

我一直在自学什么是 ManagerQuerySet 所以,我想我最好写在这里,这样下次我想知道的时候就更容易了。

Manager 是附加到模型的 class,return 是 QuerySet 实例,objects 是默认管理器。大多数经理方法,例如。 all()filter() return 个查询集实例。

更详细地说,当您执行 YourModel.objects.filter(..) 时,您会得到一个查询集实例。当你想再次过滤它时,你可以链接另一个 .filter(..) 方法,因为它在 QuerySet class 上也可用。这就是你想要的.. 在管理器和查询集上都有你的方法 returns。

如果 filter 不是管理器方法,则必须执行 YourModel.objects.all() 来获取查询集,然后 然后 添加 filter 那里的方法。

为了让事情变得简单,Django 在 QuerySet class 上定义了一个 as_manager() 方法,它将它变成一个,好吧..,一个管理器 [docs]。因此,您在查询集上定义所有自定义方法,并将其变成一个管理器,并附加到您的模型,这样您就可以在第一次调用它(作为管理器方法)并根据需要多次链接它(如查询集方法)。

写这个答案时,我想知道是否有 Django 附带的管理器方法不是查询集方法,我首先想到的是 get_or_create 方法,因为它似乎不需要一个查询集。但猜猜怎么了?这也被证明是在 QuerySet class 上定义的。

长话短说,您几乎总是想编写 QuerySet 方法并通过 as_manager() 在管理器上使用它们。