什么时候应该在 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
。
例如,假设您有一个具有 width
、height
字段的 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 查询集,或者您可能必须执行一些不涉及此特定模型的相关逻辑,而不是模型管理器它更适合。
我一直在自学什么是 Manager
和 QuerySet
所以,我想我最好写在这里,这样下次我想知道的时候就更容易了。
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()
在管理器上使用它们。
在 Django 中,自定义管理器是组织可重用查询逻辑的好方法。 Django documentation on Custom managers 表示:
There are two reasons you might want to customize a
Manager
: to add extraManager
methods, and/or to modify the initialQuerySet
theManager
returns.
但是,it goes on to describe 如何自定义 QuerySet
类 也可以创建,并且可以使用 QuerySet.as_manager()
作为管理者直接从数据模型访问这些内容:
The
Manager
instance created byQuerySet.as_manager()
will be virtually identical to thePersonManager
from the previous example.
似乎在如何组织自定义 Manager
and/or 自定义 QuerySet
类 之间的逻辑方面有很大的灵活性。我应该根据什么原则来决定何时使用其中一种与另一种?
主要是为了便于组合查询。通常,如果您希望能够在查询集调用链中对现有查询集执行某些操作,您可以使用 QuerySet
。
例如,假设您有一个具有 width
、height
字段的 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 查询集,或者您可能必须执行一些不涉及此特定模型的相关逻辑,而不是模型管理器它更适合。
我一直在自学什么是 Manager
和 QuerySet
所以,我想我最好写在这里,这样下次我想知道的时候就更容易了。
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()
在管理器上使用它们。