2

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

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?

4

1 回答 1

3

首先,你不应该覆盖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()显式调用都表现相同。

但即便如此,你所做的仍然是有问题的。正如管理器文档中所解释的,过滤默认的相关查询集将影响幕后的各种自动事物(例如在转储数据以创建备份/固定装置时等)。 你几乎绝对不想要这个。而且您真的不希望您的相关对象管理器这样做(通过设置use_for_related_fields = True),因为您将掩盖实际存储在数据库中的内容,而不是简单地检测过时的数据并创建警报或进行任何清理。 use_for_related_fields旨在创建增强普通管理器正常功能的管理器,而不是过滤。

但是我遇到了和你类似的情况,我是这样处理的:

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

至于为不同的相关对象使用不同的管理器,你真的无能为力。但是,为什么不直接将特定对象添加到您的自定义管理器中,而不是从操作 get querysets fromChannel的方法中调用它们呢?TermObject

于 2012-11-28T22:25:29.730 回答