Model Inheritance

Don’t Build Custom User Models Like This!

The following examples are a convenient way to show you how multi-table inheritance and abstract base classes work without messing up the models in your database.

This is not how you would go about creating a custom user model as it’s not connected to Django’s authentication system. Also, Django’s User class includes first_name, last_name, email and date_joined fields, so you need not create them yourself.

I will show you how to extend Django’s User class in Chapter 14.

Models are Python classes, so inheritance works the same way as normal Python class inheritance. The two most common forms of model inheritance in Django are:

  1. Multi-table inheritance, where each model has its own database table; and
  2. Abstract base classes, where the parent model holds information common to all its child classes but doesn’t have a database table.

You can also create proxy models to modify the Python-level behavior of a model without modifying the underlying model fields, however, we won’t be covering them here. See the Django documentation for more information on proxy models.

Multi-table Inheritance

With multi-table inheritance, the parent class is a normal model, and the child inherits the parent by declaring the parent class in the child class declaration. For example:

  1. # Example for illustration - don't add this to your code!
  2. class MyClubUser(models.Model):
  3. first_name = models.CharField(max_length=30)
  4. last_name = models.CharField(max_length=30)
  5. email = models.EmailField('User Email')
  6. def __str__(self):
  7. return self.first_name + " " + self.last_name
  8. class Subscriber(MyClubUser):
  9. date_joined = models.DateTimeField()

The parent model in the example is the MyClubUser model from our events app. The Subscriber model inherits from MyClubUser and adds an additional field (date_joined). As they are both standard Django model classes, a database table is created for each model. I’ve created these models in my database, so you can see the tables Django creates (Figure 9-1).

Model Inheritance - 图1

Figure 9-1: Database tables are created for both the parent and the child model. You will only see these tables if you run the example code.

Abstract Base Classes

Abstract base classes are handy when you want to put common information into other models without having to create a database table for the base class.

You create an abstract base class by adding the abstract = True class Meta option (line 7 in this illustrative example):

  1. # Example for illustration - don't add this to your code!
  2. 1 class UserBase(models.Model):
  3. 2 first_name = models.CharField(max_length=30)
  4. 3 last_name = models.CharField(max_length=30)
  5. 4 email = models.EmailField('User Email')
  6. 5
  7. 6 class Meta:
  8. 7 abstract = True
  9. 8 ordering = ['last_name']
  10. 9
  11. 10
  12. 11 class MyClubUser(UserBase):
  13. 12 def __str__(self):
  14. 13 return self.first_name + " " + self.last_name
  15. 14
  16. 15
  17. 16 class Subscriber(UserBase):
  18. 17 date_joined = models.DateTimeField()

Abstract base classes are also useful for declaring class Meta options that are inherited by all child models (line 8).

As the MyClubUser model from our events app now inherits the first name, last name and email fields from UserBase, it only needs to declare the __str__() function to behave the same way as the original MyClubUser model we created earlier.

This example is very similar to the example for multi-table inheritance in the previous section, and if you saved and migrated these models, you would get the same result as Figure 9-1—Django would create the events_myclubuser and events_subscriber tables in your database, but, because UserBase is an abstract model, it won’t be added to the database as a table.