Django gotcha: concrete inheritance
Since 1.0, Django’s supported model inheritance. It’s a neat feature, and can go a long way towards increasing flexibility in your modeling options.
However, model inheritance also offers a really excellent opportunity to shoot yourself in the foot: concrete (multi-table) inheritance. If you’re using concrete inheritance, Django creates implicit joins back to the parent table on nearly every query. This can completely devastate your database’s performance.
To refresh, if you’ve got models like:
class Person(Model): name = CharField() ... class Manager(Person): department = CharField() ...
That’s concrete inheritance. Django creates two tables: a
table and a
Manager table. Since the
name field will only exist on
Person table, every time you look up a
Manager Django will use
to generate a join against the
Person table to get the
name. These joins tend to be “hidden” – they’re created automatically
– and mean that what look like simple queries often aren’t.
If, on the other hand, you’ve got models like:
class Person(Model): name = CharField() ... class Meta: abstract = True class Manager(Person): ...
That’s abstract inheritance and Django only creates a single table,
Manager table. Any model that subclasses
Person will have the
Person’s fields copied onto the child object. This means that looking
Manager doesn’t require an extra join.
In nearly every case, abstract inheritance is a better approach for the long term. I’ve seen more than few sites crushed under the load introduced by concrete inheritance, so I’d strongly suggest that Django users approach any use of concrete inheritance with a large dose of skepticism.