The Metaclass approach proposed by thedk is indeed a very powerful way to go, however, I had to combine it with an answer to the question here to have the query return a proxy model instance. The simplified version of the code adapted to the previous example would be:
from django.db.models.base import ModelBase
class InheritanceMetaclass(ModelBase):
def __call__(cls, *args, **kwargs):
obj = super(InheritanceMetaclass, cls).__call__(*args, **kwargs)
return obj.get_object()
class Animal(models.Model):
__metaclass__ = InheritanceMetaclass
type = models.CharField(max_length=255)
object_class = models.CharField(max_length=20)
def save(self, *args, **kwargs):
if not self.object_class:
self.object_class = self._meta.module_name
super(Animal, self).save( *args, **kwargs)
def get_object(self):
if self.object_class in SUBCLASSES_OF_ANIMAL:
self.__class__ = SUBCLASSES_OF_ANIMAL[self.object_class]
return self
class Dog(Animal):
class Meta:
proxy = True
def make_sound(self):
print "Woof!"
class Cat(Animal):
class Meta:
proxy = True
def make_sound(self):
print "Meow!"
SUBCLASSES_OF_ANIMAL = dict([(cls.__name__, cls) for cls in ANIMAL.__subclasses__()])
The advantage of this proxy approach is that no db migration is required upon creation of new subclasses. The drawback is that no specific fields can be added to the subclasses.
I would be happy to have feedback on this approach.