Is there a way to determine what the 'real' class of a Django database object is, after it has been returned from a query for on a base class?
For instance, if I have these models...
class Animal(models.Model):
name= models.CharField(max_length=128)
class Person(Animal):
pants_size = models.IntegerField(null=True)
class Dog(Animal):
panting_rate = models.IntegerField(null=True)
And create these instances...
Person(name='Dave').save()
Dog(name='Mr. Rufflesworth').save()
If I do a query like Animal.objects.all()
, I end up with two Animal
instances, not an instance of Person
and an instance of Dog
. Is there any way to determine which instance is of which type?
FYI: I already tried doing this...
isinstance(Animal.objects.get(name='Dave'),Person) # <-- Returns false!
But that doesn't seem to work.
I had a similar problem in the past and eventually found a satisfactory solution thanks to this answer.
By implementing an abstract class that stores the real class and have it inherited by your parent class, once can cast each parent class instance to the actual type. (The abstract class used in that answer is now available in django-model-utils.)
For example, once you have the abstract class defined (or if you have django-model-utils), you can simply do:
class Animal(InheritanceCastModel):
name= models.CharField(max_length=128)
class Person(Animal):
pants_size = models.IntegerField(null=True)
class Dog(Animal):
panting_rate = models.IntegerField(null=True)
Using it is trivial:
>>> from zoo.models import Animal, Person, Dog
>>> Animal(name='Malcolm').save()
>>> Person(name='Dave').save()
>>> Dog(name='Mr. Rufflesworth').save()
>>> for obj in Animal.objects.all():
... print obj.name, type(obj.cast())
...
Malcolm <class 'zoo.models.Animal'>
Dave <class 'zoo.models.Person'>
Mr. Rufflesworth <class 'zoo.models.Dog'>