Django ORM继承了ManyToMany字段

时间:2010-11-10 18:27:15

标签: django orm inheritance

假设我有以下ORM类(删除字段以简化):

class Animal(models.Model):
    say = "?"

    def say_something(self):
        return self.say

class Cat(Animal):
    self.say = "I'm a cat: miaow"

class Dog(Animal):
    self.say = "I'm a dog: wuff"

class Animals(models.Model):
    my_zoo = models.ManyToManyField("Animal")

当我向动物园添加一些动物时:

cat = Cat()
cat.save()
dog = Dog()
dog.save()

animals.my_zoo.add(cat)
animals.my_zoo.add(dog)

for animal in animals.my_zoo.all():
    print animal.say_something()

......我希望得到以下结果:

我是一只猫:miaow,我是一只狗:wuff

但相反,我所拥有的只是一般Animal对象的实例,除了“?”之外什么都不能说。

当从db中检索对象时,如何实现真正的对象继承和后来的多态?

2 个答案:

答案 0 :(得分:4)

django中的模型继承不会向基类添加任何类型信息。因此,不可能将对象从Animal()向下转换为适当的形式。

继承仅用于将继承模型上的字段映射回父模型。因此,如果Animal有字段name,则Cat上会存在相同的字段,当您保存Cat时,animal将会更新。

通过添加OneToOne关系继承:

class Animal(Model):
    name = CharField()

class Cat(Model):
    animal_ptr = OneToOneField(Animal)

Cat(name='Murky').save()

print repr(list(Animals.objects.all()))

: [Animal(name='Murky')]

从技术上讲,在你的情况下,Animal()甚至可以同时同时是Dog()和Cat():

animal = Animal()
animal.save()

Cat(animal_ptr=animal).save()
Dog(animal_ptr=animal).save()

解决问题的方法是添加一个字段subtype或类似于Animal()对象并实现向下转换功能:

class Animal(Model):
    subtype = CharField()

    def downcast(self):
        if self.subtype == 'cat':
            return self.cat
            # The self.cat is a automatic reverse reference created
            # from OneToOne field with the name of the model

for animal in Animal.objects.all().select_related('dog', 'cat', ...)]:
    animal.downcast().say_something()

有关类似主题的堆栈溢出的一些有用读取: Generic many-to-many relationships他引擎盖。 How to do Inheritance Modeling in Relational Databases?

答案 1 :(得分:0)

您可以通过attribute on the parent class访问后代。属性的名称是模型名称的小写版本:

class Animal(models.Model):
    say = "?"

    def say_something(self):
        for animal in ('cat', 'dog'):
            try:
                return getattr(self, animal).say
            except:
                pass
            return self.say