Reputation: 59202
Short version:
With multi-table inheritance in Django, given a model object of a derived class, is it possible to obtain the corresponding base class model object, without making an additional database query?
Long version:
I'm using multi-table inheritance in my Django application. I have a situation where the base class defines certain methods which are overridden by the derived class, but I actually want to call the base class methods. Here's an example:
from django.db import models
class Animal(models.Model):
name = models.CharField(max_length=100)
def speak(self):
return "generic animal noise"
def foo(self):
...
def bar(self):
...
def baz(self):
...
class Dog(Animal):
breed = models.CharField(max_length=100)
def speak(self):
return "Arf"
def foo(self):
...
def bar(self):
...
def baz(self):
...
I have a reference to a model object of type Dog, and I want to call the Animal.speak method on it, not the Dog.speak method. I know that I can do this:
dog = Dog.objects.get(name="rover")
Animal.speak(dog)
However, in the code I'm writing, there are multiple methods that are overridden that I need to call, and so instead of doing:
Animal.foo(dog)
Animal.bar(dog)
Animal.baz(dog)
...
I'd prefer to be able to do an upcast and then have all of the calls resolve to the base class's method:
animal = upcast_to_animal(dog)
animal.foo()
animal.bar()
animal.baz()
I know one way to implement upcast_to_animal, but it requires making a database query:
def upcast_to_animal(x):
return Animal.objects.get(pk=x.pk)
My question is: is it possible to implement that "upcast_to_animal" method without making an additional query to the database?
Upvotes: 1
Views: 484
Reputation: 39659
Just a simple demonstration (up casting):
class Animal(models.Model):
name = models.CharField(max_length=30)
def foo(self):
print 'hello animal'
class Dog(Animal):
name_me = models.CharField(max_length=30)
def foo(self):
print 'hello dog'
# django shell
>>> dog = Dog.objects.create(name_me='bull dog')
>>> dog.foo()
hello dog
>>> animal = super(dog.__class__, dog)
>>> animal.foo()
hello animal
Upvotes: 4
Reputation: 16796
How about:
import copy
animal = copy.deepcopy(dog)
animal.__class__ = Animal
Upvotes: 0