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 Person
table and a Manager
table. Since the name
field will only exist on
the Person
table, every time you look up a Manager
Django will use
to generate a join against the Person
table to get the Manager
’s
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,
the Manager
table. Any model that subclasses Person
will have the
Person’s fields copied onto the child object. This means that looking
up a 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.