Lorin Hochstein
Lorin Hochstein

Reputation: 59202

Django: multi-table inheritance and upcasting without a database query

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

Answers (2)

Aamir Rind
Aamir Rind

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

dgel
dgel

Reputation: 16796

How about:

import copy

animal = copy.deepcopy(dog)
animal.__class__ = Animal

Upvotes: 0

Related Questions