什么时候应该使用自定义管理器而不是Django中的自定义QuerySet?

时间:2015-04-22 12:49:51

标签: python django orm django-managers

在Django中,自定义管理器是组织可重用查询逻辑的好方法。 docs状态有两个原因可能需要自定义Manager:添加额外的Manager方法,和/或修改Manager返回的初始QuerySet。

但是,it goes on to describe如何创建自定义QuerySet,并且可以通过QuerySet.as_manager()直接从数据模型作为管理员访问这些查询集。 QuerySet.as_manager()创建的Manager实例与前一个示例中的PersonManager几乎完全相同。

似乎在如何在自定义Manager和/或自定义QuerySet之间组织逻辑方面有很大的灵活性。有人可以解释我应该决定何时使用其中一种的原则吗?

2 个答案:

答案 0 :(得分:24)

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

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

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()

逻辑上,这些函数应主要关注查询集模型的现有查询集的分区或重新定义。对于您不在现有查询集上运行的情况,您根本不想返回查询集,或者您可能必须执行一些不涉及此特定模型的相关逻辑,而不是模特经理更适合。

答案 1 :(得分:5)

我不断地自我介绍ManagerQuerySet是什么,所以,我认为我最好在这里写,这样下次我想知道就更容易了。

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

更详细地讲,当您执行YourModel.objects.filter(..)时,将获得一个queryset实例。当您想再次对其进行过滤时,可以链接另一个.filter(..)方法,因为它也可以在QuerySet类中使用。那就是您想要的..在管理器和它返回的查询集上都有您的方法。

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

为使事情变得容易,Django在QuerySet类上定义了一个as_manager()方法,这使它变成了一个管理器[docs]。因此,您可以在查询集上定义所有自定义方法,并将其转变为管理器,然后附加到模型,这样您就可以第一次调用它(作为管理器方法)并根据需要进行多次链接(根据需要) queryset方法)。

写下这个答案,我想知道Django附带的管理器方法不是queryset方法,我想到的第一个方法是get_or_create方法,因为它似乎不需要查询集。但猜猜怎么了?事实证明,它也是在QuerySet类上定义的。

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