我想知道是否有可能(如果可能的话,如何)将多个管理器链接在一起,生成一个受这两个单独管理器影响的查询集。我将解释我正在研究的具体示例:
我有多个抽象模型类,用来为其他模型提供小的、特定的功能。其中两个模型是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()
基本上,它提供了一个伪删除(deleted标志),而不是实际删除对象。
GlobalMixin的定义如下:
class GlobalMixin(models.Model):
is_global = models.BooleanField(default=True)
objects = GlobalManager()
class Meta:
abstract = True
它允许将任何对象定义为全局对象或私有对象(例如公共/私有博客文章)。
它们都有自己的管理器,影响返回的queryset。我的DeleteManager将queryset过滤为只返回deleted标志设置为False的结果,而GlobalManager将queryset过滤为只返回标记为全局的结果。以下是这两种情况的声明:
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个实例的模型上运行了一个测试用例:一个是全局和非删除的,一个是全局和删除的,一个是非全局和非删除的,还有一个是非全局和删除的。如果我试图得到结果集:SOMMODEL。对象。(),我得到实例1和3(两个未删除的-太好了!)如果我尝试SomeModel.objects.globals(),就会得到一个DeleteManager没有globals的错误(这是假设我的模型声明是这样的:SomeModel(DeleteMixin,GlobalMixin)。如果我颠倒顺序,我不会得到错误,但它不会过滤掉删除的错误)。如果我将GlobalMixin更改为将GlobalManager附加到globals而不是对象(因此新命令将是SomeModel.globals.globals()),我将获得实例1和2(两个globals),而我的预期结果将是仅获取实例1(全局的、未删除的)。
我不确定是否有人遇到过类似的情况,并取得了结果。无论是让它在我当前的思维中工作,还是提供我所追求的功能的重新工作,都将非常感谢。我知道这篇文章有点冗长。如果需要更多的解释,我很乐意提供。
编辑:
我已经在下面发布了我对这个特定问题的最终解决方案。它基于到Simon的自定义QuerySetManager的链接。
在Djangosnippets上看到这个片段:http://djangosnippets.org/snippets/734/
不要将自定义方法放在管理器中,而是对queryset本身进行子类化。它非常简单,工作得很好。我遇到的唯一问题是模型继承,您总是必须在模型子类中定义管理器(子类中的“objects=queryset manager()”),即使它们将继承queryset。使用QuerySetManager后,这将更有意义。
下面是使用Scott链接到的Simon定制的QuerySetManager解决我的问题的具体方法。
将来任何想向查询集添加额外功能的mixin都只需要扩展BaseMixin(或者将其放在其继承结构中的某个位置)。每当我试图过滤设置的查询时,我都会将它包装在一个try catch中,以防该字段实际上不存在(即,它不扩展该mixin)。全局过滤器是使用globals()调用的,而delete过滤器是自动调用的(如果删除了某些内容,我永远不希望它显示出来)。使用此系统可以执行以下类型的命令:
需要注意的一点是,delete过滤器不会影响管理界面,因为默认管理器首先声明(使其成为默认管理器)。我不记得他们何时将管理员更改为使用Model.\u default\u manager而不是Model.objects,但是任何已删除的实例仍将显示在管理员中(以防您需要取消删除它们)。
我花了一段时间想办法建一个好工厂,但我遇到了很多问题。
我能给你的建议是把你的遗产连锁起来。它不是很通用的,所以我不确定它有多有用,但你要做的就是:
如果你想要更通用的东西,我能想到的最好方法是定义一个基
Mixin
和Manager
来重新定义get_query_set()
(我假设你只想这样做一次;否则事情会变得非常复杂),然后通过Mixin
传递一个要添加的字段列表它看起来像这样(根本没有经过测试):
好吧,这很难看,但你觉得怎么样?从本质上说,这是相同的解决方案,但更具活力,也更干燥,尽管阅读起来更复杂。
首先,动态创建管理器:
这将创建一个新的管理器,它是
DeleteManager
的子类,并且有一个名为globals
的方法。接下来,创建mixin模型:
就像我说的,很难看。但这意味着你不必重新定义
globals()
。如果您希望不同类型的管理器具有globals()
,只需使用不同的基再次调用create_manager
。你可以添加任意多的新方法。同样对于管理器,您只需不断添加新函数,这些函数将返回不同的queryset。那么,这真的实用吗?也许不是。这个答案更多的是(ab)使用Python的灵活性。我没有尝试过使用它,尽管我确实使用了一些动态扩展类的基本原理,以使访问更容易。
如果有什么不清楚的地方请告诉我,我会更新答案。
相关问题 更多 >
编程相关推荐