edk*_*rin 5 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")
Run Code Online (Sandbox Code Playgroud)
当我向动物园添加一些动物时:
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()
Run Code Online (Sandbox Code Playgroud)
...我希望得到以下结果:
我是猫:喵,我是狗:wuff
但是相反,我所拥有的只是一般 Animal 对象的实例,除了“?”之外什么都不能说。
从db中取出对象时,如何实现真正的对象继承和后来的多态?
django 中的模型继承不会向基类添加任何类型信息。所以实际上不可能将对象从 Animal() 向下转换为适当的形式。
继承仅用于将继承模型上的字段映射回父模型。因此,如果 Animal 有 field name,则相同的 field 将存在,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')]
Run Code Online (Sandbox Code Playgroud)
从技术上讲,在您的情况下,Animal() 甚至可能同时是 Dog() 和 Cat():
animal = Animal()
animal.save()
Cat(animal_ptr=animal).save()
Dog(animal_ptr=animal).save()
Run Code Online (Sandbox Code Playgroud)
解决您的问题的方法是添加一个字段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()
Run Code Online (Sandbox Code Playgroud)
一些有用的关于堆栈溢出的类似主题的阅读: 通用的多对多关系he hood。 如何在关系数据库中进行继承建模?