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.