Let's say I have following ORM classes (fields removed to simplify):
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")
When I add some animals to my zoo:
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()
... I would expect following result:
I'm a cat: miaow, I'm a dog: wuff
but instead, all I've got is the instances of general Animal object, unable to say anything but "?".
How to achieve the true object inheritance and later polymorphism when the object is retreived from db?
Model inheritance in django does not add any type information to the base class. So it is not really possible to down-cast objects down from Animal() to their appropriate forms.
Inheritance is used only to map fields on inherited model back to parent models. So if Animal has field name
, the same field will exist on Cat
and when you save Cat
, the animal
will be updated.
Inheritance works by adding a OneToOne relation:
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')]
Technically in your situation it is even possible for Animal() to be both Dog() and Cat() at the same time:
animal = Animal()
animal.save()
Cat(animal_ptr=animal).save()
Dog(animal_ptr=animal).save()
The way to solve your problem would be to add a field subtype
or similar to your Animal()
object and implement downcasting function:
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()
A few useful reads on stack overflow with similar topics: Generic many-to-many relationships he hood. How to do Inheritance Modeling in Relational Databases?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With