In object-oriented languages, such as Python, a mixin class can be viewed as an interface with implemented features. When a model extends a mixin, it implements the interface and includes all of its fields, attributes, properties, and methods. The mixins in Django models can be used when you want to reuse the generic functionalities in different models multiple times. The model mixins in Django are abstract base model classes. We will explore them in the next few recipes.
Using model mixins
Getting ready
First, you will need to create reusable mixins. A good place to keep your model mixins is in a myproject.apps.core app. If you create a reusable app that you will share with others, keep the model mixins in the reusable app itself, possibly in a base.py file.
How to do it...
Open the models.py file of any Django app that you want to use mixins with, and type the following code:
# myproject/apps/ideas/models.py
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from myproject.apps.core.models import (
CreationModificationDateBase,
MetaTagsBase,
UrlBase,
)
class Idea(CreationModificationDateBase, MetaTagsBase, UrlBase):
title = models.CharField(
_("Title"),
max_length=200,
)
content = models.TextField(
_("Content"),
)
# other fields…
class Meta:
verbose_name = _("Idea")
verbose_name_plural = _("Ideas")
def __str__(self):
return self.title
def get_url_path(self):
return reverse("idea_details", kwargs={
"idea_id": str(self.pk),
})
How it works...
Django's model inheritance supports three types of inheritance: abstract base classes, multi-table inheritance, and proxy models. Model mixins are abstract model classes, in that we define them by using an abstract Meta class, with specified fields, properties, and methods. When you create a model such as Idea, as shown in the preceding example, it inherits all of the features from CreationModificationDateMixin, MetaTagsMixin, and UrlMixin. All of the fields of these abstract classes are saved in the same database table as the fields of the extending model. In the following recipes, you will learn how to define your model mixins.
There's more...
In normal Python class inheritance, if there is more than one base class, and all of them implement a specific method, and you call that method on the instance of a child class, only the method from the first parent class will be called, as in the following example:
>>> class A(object):
... def test(self):
... print("A.test() called")
...
>>> class B(object):
... def test(self):
... print("B.test() called")
...
>>> class C(object):
... def test(self):
... print("C.test() called")
...
>>> class D(A, B, C):
... def test(self):
... super().test()
... print("D.test() called")
>>> d = D()
>>> d.test()
A.test() called
D.test() called
This is the same for Django model base classes; however, there is one special exception.
That means that you can confidently do pre-save, post-save, pre-delete, and post-delete manipulations for specific fields defined specifically in the mixin by overwriting the save() and delete() methods.
To learn more about the different types of model inheritance, refer to the official Django documentation, available at https://docs.djangoproject.com/en/2.2/topics/db/models/#model-inheritance.
See also
- The Creating a model mixin with URL-related methods recipe
- The Creating a model mixin to handle creation and modification dates recipe
- The Creating a model mixin to take care of meta tags recipe