Model inheritance. How to 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 elements of type ChildA
. Why, when I ask for the __unicode__()
appropriate Parent
, is the string I get in return the one generated by the method __unicode__()
Child
and not the method __unicode__()
ChildA
?
Update:
This is standard behavior. Other possible solutions in addition to below answers are inheritance inheritance
This is the standard behavior for inheritance. Parent
is directly related to Child
, not ChildA
. When you call some_parent.children.all()
, you return a set of instance requests Child
, so obviously when you call unicode
on one of them, it calls Child.__unicode__
.
UPDATE
There's not a very good way to get from parent to child. If you are using MTI (Multiple Table Inheritance), you can take advantage of the way Django implements it, namely as OneToOneField
a parent. There is also parent-child feedback because of this, but you must specifically test 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
...
This is not ideal and you need to be careful to always update this method whenever you subclass Child
, which pretty much completely breaks abstraction in OOP.
You probably want an abstract base class.
Read the difference here ... https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes
Why, when I ask the unicode () of the corresponding parent, the line I get in return is the one generated by the unicode () method of the Child?
It follows that you are not calling a method on an instance Parent
. This is why you see this behavior.
You can access the parent class method using the keyword super()
:
a = ChildA()
#This will give you the normal method:
print unicode(a)
#super() will give you the parent method:
super(ChildA, a).__unicode__()
You cannot just use the function unicode()
with the last call, as it super
returns a proxy for the object, not a native object.
This is not the best way to code. Leave it up to the class to override the behavior as you see fit.