Django,覆盖多对多字段ModelManager

时间:2012-11-28 17:10:29

标签: python django model

如何覆盖我考虑过以下内容的多对多字段的模型管理器:

class TermsManager(models.Manager):
    def all(self):
        return super(TermsManager, self).all().filter(condition_here)


class Term(models.Model):
    objects = TermsManager()

    name = models.CharField(max_length=255)

class Object(models.Model):        
    title = models.CharField(max_length=255)
    terms = models.ManyToManyField(Term, blank=True)

class Channel(Object):
    class Meta:
        proxy = True

我还有一个继承自TermManager的类,名为ChannelTermManager。 如何覆盖Channel模型的“terms”字段 mychannel.terms调用ChannelTermManager而不是TermManager?

1 个答案:

答案 0 :(得分:2)

首先,你不应该覆盖all()。如果要更改默认查询集,请覆盖get_query_set,如下所示:

class TermsManager(models.Manager):
    def get_query_set(self):
        return super(TermsManager, self).get_query_set().filter(condition_here)

这是因为当链接其他查询集函数时,all()经常被省略,并且您希望查询集的行为相同,无论是否显式调用all()

但即便如此,你所做的仍然是有问题的。如documentation for managers中所述,过滤默认的相关查询集将影响幕后的各种自动操作(例如,在转储数据以创建备份/夹具等时)。 你几乎肯定不想要这个。并且您真的不希望您的相关对象管理器这样做(通过设置use_for_related_fields = True),因为您将屏蔽实际存储在数据库中的内容,而不是简单地检测过时数据并创建警报或其他清理它。 use_for_related_fields用于创建管理器,以增强vanilla管理器的正常功能,而不是过滤。

然而,我遇到了类似的情况,我这样处理了它:

class FilteredTermsManager(models.Manager):
    def get_query_set(self):
        return super(TermsManager, self).get_query_set().filter(condition_here)

class Term(models.Model):
    allTerms = models.Manger() # Establish this as the default/automatic manager
    objects = FilteredTermsManager()

    name = models.CharField(max_length=255)

这样,我可以通过我的过滤查询集对模型进行所有初始查询,它看起来像“常规Django”,但所有关系和幕后查询都可以在未过滤的数据库上运行。我总是可以通过手动执行Term.allTerms.all()来访问真正的完整对象。

至于为不同的相关对象使用不同的管理器,那里没有什么可以真正做到的。但是,为什么不将Channel个特定对象添加到自定义管理器中,而不是从Term来自Object查询集的操作方法中调用它们?