After encountering difficulties installing CouchDB on Webfaction (Still a work in progress - let me know if you've had success!) I decided to try and back port some of my CouchDB refactor to the Django ORM. I'd not really used any of the model inheritance functionality, so assumed it would follow the classical pythonic inheritance model. Unfortunately it seems that instead the Django team have decided to use a lesser form using a 'has a' relationship instead of the traditional 'is a'.
What this means in practice is that subclasses, while accessible through the managers of their superclasses, are not first class citizens. Thus, the example in the django documentation:
>>> p = Place.objects.filter(name="Bob's Cafe")
# If Bob's Cafe is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>
Here you can see that, rather than restaurant being a specialised version of place, it is in fact a separate entity with a one to one mapping between the two. This, I guess, was the reason behind the team choosing to implement this form of inheritance - it maps to the RDBS model very smoothly. It is also the reason I fundamentally disagree with it - ORM's are designed to abstract the database to make the interface more like the language. In this situation, the ORM has chosen to be less pythonic in order to keep the backend implementation more simple.
The consequences are quite annoying. What I want is to have a generic, but not abstract, model, and certain specialisations of this model. I wish to be able to override the subclasses to provide different fuctionality. Specifically - I wish to have a generic Article class that will store postings to my website, but subclass it when further funcionality is required, for example when posting a photo. In this situation, the content attribute has a different semantic meaning. I wish to generate the content from the other attributes in the case of the Photo.
Unfortunately, with the way inheritance is implemented in Django, I cannot simply override the content property in my Photo model. Because the extra data is only stored in the Photo table, I either have to check whether each instance is a photo in all of my views so I can use the relationship to access the method (which violates the duck typing principle) or I have to have Photo specific logic within my Article model (violating encapsulation). It is unfortunate that this is the way it has been implemented. I'm going to try and find a workaround, because neither of these situations are satisfactory.


This is not an open forum — abusive or worthless comments will be deleted
You wouldn't have to check each instance, you can just access the method as if you know that there is a photo and then catch the exception in case there isn't one. That is duck typing.
Hi Julian,
Unfortunately this is the problem - you can't simply access the photo's methods - by default you are returned an object of the superclass's type, and to access the subclasses methods you must do ie: article.photo.foo()
This unfortunately is another query.
I don't think exception oriented programming is a panacea to the ramifications of this design decision. I believe there must be a way to allow pythonic inheritance, but I'm still looking for it.
I found the following page to be useful; I am just starting out with a project that could involve subclassing Models: http://www.pubbs.net/django/200908/46585/
In particular the suggestion of Russell Keith-Magee of adding a "narrow" method seems interesting, such that objects returned from a query could get correctly "specified" with a list comprehension:
[ obj.narrow() for obj in BaseClass.objects.all() ]
Is there any news for solving this problem?
http://stackoverflow.com/questions/1581024/django-inheritance-how-to-have-one-method-for-all-subclasses
http://www.hopelessgeek.com/2009/11/25/a-hack-for-multi-table-inheritance-in-django
Seems very interesting.
I fundamentally agree with you. I posted today on Django Developers (Google Group), only to find your post from a while back. It was alarming that it didn't take hold. I don't propose a way to handle the complexity of the ORM while removing these obstacles but I will say it is very un-Pythonic and partly useless to even use Django's multi-table inheritance without being able to override parent class attributes. The biggest use right out the gate would be contrib.auth.User ( for me ).