Ohad
Ohad

Reputation: 1719

Model inheritance - How can I use overridden methods?

I have the following code:

   # apps/models.py :

class Parent(models.Model):
    name = models.CharField(max_length=80)

    def __unicode__(self):
        clist = ", ".join([x.__unicode__() for x in self.children.all()])
        return self.name + clist

class Child(models.Model):  
    unit = models.ForeignKey(Parent, related_name='children')
    desc = models.CharField(max_length=80)

    def __unicode__(self):
         return self.desc

class ChildA(Child):
    text = models.TextField()

    def __unicode__(self):
         return self.text[:40]

I have several items of type ChildA. Why when I ask for a __unicode__() of the relevant Parent, the string I get in return is the one generated by the __unicode__() method of Child and not the __unicode__() method of ChildA ?

Updates:

This is standard behavior. Another possible solutions in addition to answers below is an inheritance cast

Upvotes: 5

Views: 3540

Answers (4)

Chris Pratt
Chris Pratt

Reputation: 239220

This is standard behavior for inheritance. Parent is related directly with Child, not ChildA. When you call some_parent.children.all(), you get back a queryset of Child instances, so obviously, when you call unicode on one of those, it's calling Child.__unicode__.

UPDATE

There's not really a good way to get from a parent to the child. If you're using MTI (Multiple Table Inheritance), you can take advantage of the way Django implements it, namely as a OneToOneField with the parent. Because of that, there's also a reverse relationship on the parent to the child, but you must specifically test for it. For example:

class Child(models.Model):
    ...
    def get_child(self):
        if hasattr(self, 'childa'):
            return self.childa
        if hasattr(self, 'childb'):
            return self.childb
        ...

It's not ideal by any means, and you need to be careful to always update this method whenever you subclass Child, which pretty much totally violates abstraction in OOP.

Upvotes: 5

Steve Mayne
Steve Mayne

Reputation: 22808

You can access the parent class's method by using the super() keyword:

a = ChildA()

#This will give you the normal method:
print unicode(a)

#super() will give you the parent's method:
super(ChildA, a).__unicode__()

You cannot simply use the unicode() function with the latter call, as super returns a proxy to the object, rather than an object in its own right.

This is not a good way to code. Leave it up to the class to override behaviour as it sees fit.

Upvotes: 0

Marcin
Marcin

Reputation: 49816

Why when I ask for a unicode() of the relevant parent the string I get in return is the one generated by the unicode() method of Child ?

It follows that you are not calling the method on a Parent instance. That is why you are seeing this behaviour.

Upvotes: 0

user391538
user391538

Reputation:

You probably want an abstract base class.

Read up on the difference here... https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes

Upvotes: 0

Related Questions