Django:如何级联在不同抽象类中定义的自定义管理器?

时间:2014-08-06 12:51:35

标签: django django-managers

我希望能够组合来自不同Abstract类的不同自定义管理器函数的复杂查询。

我的模特是这样的:

class GenderManager(models.Manager):
    def male(self):
        return self.filter(gender="M")

    def female(self):
        return self.filter(gender="F")


 class SpeciesManager(models.Manager):
    def lion(self):
        return self.filter(species="L")

    def tiger(self):
        return self.filter(species="T")


class GenderModel(models.Model):
    gender = models.CharField(max_length=1)
    objects = GenderManager()

    class Meta:
        abstract = True


class SpeciesModel(models.Model):
    species = models.CharField(max_length=1)
    objects = SpeciesManager()

    class Meta:
        abstract = True


class Animal(GenderModel,SpeciesModel):
    name = models.CharField(max_length=30)
    age = models.DecimalField(max_digits=4, decimal_places=2)

我想分割性别和物种的原因是,在我的模型中,有时我只需要从GenderModel继承,有时只需要从SpeciesModel继承。

在我想继承表单的情况下(比如在Animal类中),我希望能够进行这样的查询:

Animal.objects.male().tiger().filter(age__gte = 10.00)

但它不起作用。

但是,如果我不使用自定义管理器功能,它可以工作:

Animal.objects.filter(gender="M").filter(species="T").filter(age__gte = 10.00)

如何使其与自定义管理器功能一起使用,确实让它变干?

谢谢!

2 个答案:

答案 0 :(得分:1)

由于Managers实际工作的方式无法做到这一点,但可以采用不同的方法来重构模型和逻辑,具体取决于复杂性以及模型实际需要的独立性。

由于您的经理实际上是需要具体类而不是抽象类,因此将两个管理器合并为一个管理器,毕竟您是在过滤具体类而不是抽象。

class GenderModel(models.Model):
    gender = models.CharField(max_length=1)

    class Meta:
        abstract = True


class SpeciesModel(models.Model):
    species = models.CharField(max_length=1)

    class Meta:
        abstract = True


class AnimalManager(models.Manager):
    def gender(self):
        return self.filter(gender="M")

    def female(self):
        return self.filter(gender="F")

    def lion(self):
        return self.filter(species="L")

    def tiger(self):
        return self.filter(species="T")

    def get_male_tigers(self):
        return self.filter(species="T").filter(gender="M").all()

class Animal(GenderModel,SpeciesModel):
    name = models.CharField(max_length=30)
    age = models.DecimalField(max_digits=4, decimal_places=2)
    objects = AnimalManager()

然后:

 animals = Animal.objects.get_male_tigers()

当然,您可以进一步重构您的需求

答案 1 :(得分:0)

当然,

objects不能同时引用GenderManagerSpeciesManager。鉴于MRO的工作原理,在您的示例中,它是SpeciesManager实例。

您可以创建第三个经理:

class AnimalManager(GenderManager, SpeciesManager):
    def male_and_tiger(self):
        return self.male & self.tiger()

    [all other combinations here]

class Animal(GenderModel,SpeciesModel):
    [...]
    objects = AnimalManager()

但是我真的认为你被OOP继承恶魔所拥有了:)对orm的简单调用更好,更有前途证明(除非你想每次都为你的SpeciesManager添加新方法添加新物种)