我在思考是否可能(如果可能的话,如何)将多个管理器链接在一起,从而生成一个同时受到这些管理器影响的查询集。我将解释我正在处理的具体示例:
我有多个抽象模型类,用于向其他模型提供小型、特定的功能。其中两个模型是DeleteMixin和GlobalMixin。
DeleteMixin的定义如下:
class DeleteMixin(models.Model):
deleted = models.BooleanField(default=False)
objects = DeleteManager()
class Meta:
abstract = True
def delete(self):
self.deleted = True
self.save()
基本上它提供了一种伪删除(即删除标志),而不是实际删除对象。GlobalMixin 定义如下:
class GlobalMixin(models.Model):
is_global = models.BooleanField(default=True)
objects = GlobalManager()
class Meta:
abstract = True
它允许任何对象定义为全局对象或私有对象(例如公共/私有博客文章)。
这两者都有自己的管理器,影响返回的查询集。我的DeleteManager将查询集过滤,仅返回已将删除标志设置为False的结果,而GlobalManager将查询集过滤,仅返回标记为全局的结果。以下是两者的声明:
class DeleteManager(models.Manager):
def get_query_set(self):
return super(DeleteManager, self).get_query_set().filter(deleted=False)
class GlobalManager(models.Manager):
def globals(self):
return self.get_query_set().filter(is_global=1)
期望的功能是有一个模型可以扩展这两个抽象模型并且允许只返回既非删除的又是全局的结果。我针对拥有4个实例的模型运行了一项测试用例:其中一个实例是全局的并且未被删除,第二个是全局的但已被删除,第三个是非全局且未被删除的,第四个是非全局且已被删除的。如果我尝试获取如下的结果集:SomeModel.objects.all(),我将得到实例1和3(即两个未被删除的实例-很好!)。如果我尝试SomeModel.objects.globals(),我会收到一个错误消息,指出DeleteManager没有globals方法(这是基于我的模型声明为SomeModel(DeleteMixin, GlobalMixin)的情况)。如果我反转顺序,则不会出现错误,但它不会过滤掉已删除的实例。如果我将GlobalMixin更改为将GlobalManager附加到globals而不是objects上(因此新命令将是SomeModel.globals.globals()),我将得到实例1和2(即两个全局实例),而我想要的结果是只获取实例1(即全局、未被删除的实例)。我不确定是否有人遇到过类似的情况并得出了结果。不管是在当前思路下使其工作的方法还是提供所需功能的重新设计都将非常感激。我知道这篇文章有点啰嗦。如果需要更多解释,我很乐意提供。
编辑:我在下面发布了我用于解决这个特定问题的最终解决方案。它基于Simon的自定义QuerySetManager的链接。