Mixin in Django is a Python class inherited by another class to accomplish additional functionality. Mixins are reusable and scalable classes.

Prerequisite: Understanding Django’s class-based views is required before exploring Mixins.

How Mixin works in Django

Let me take an example, to help you understand the working of a mixin.

Suppose you want only logged-in users to have access to an URL. For this, you can use Django's built-in LoginRequiredMixin in your view, just like the code snippet below.

 from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

LoginRequiredMixin overrides one or more methods of the View class to achieve this functionality. You don't need to delve into the exact methods at this point for the sake of simplicity of this tutorial, this is just to give an idea of how mixin works. You will get a clear understanding, once you create a custom mixin.

Create a custom mixin in Django

Let's create a mixin that redirects a user based on some condition.

Before that, you need to know why to create a mixin. Well, if you don't create a mixin then you have to write the redirect logic to every view and also if you have to update redirect logic at a later point of time then you have to make changes at every view.

In Django's class-based views, there is a method called dispatch, that you will have to override to achieve any mixin-related functionality.

Let's consider the below code snippet as your view that is called when a user logged in.

from django.views.generic import TemplateView

class LoginView(TemplateView):
    template_name="account/login.html"

Now you have to create two python classes to create the redirect mixin. First, create a GENERIC mixin to be used by any other mixin for redirecting.

from django.core.exceptions import ImproperlyConfigured
from django.shortcuts import redirect

class RedirectMixin:
    """
    Redirect to redirect_url if the test_func() method returns False.
    """

    redirect_url = None

    def get_redirect_url(self):
        """
        Override this method to override the redirect_url attribute.
        """
        redirect_url = self.redirect_url
        if not redirect_url:
            raise ImproperlyConfigured(
                '{0} is missing the redirect_url attribute. Define {0}.redirect_url or override '
                '{0}.get_redirect_url().'.format(self.__class__.__name__)
            )
        return str(redirect_url)

    def test_func(self):
        raise NotImplementedError(
            '{0} is missing the implementation of the test_func() method.'.format(self.__class__.__name__)
        )

    def get_test_func(self):
        """
        Override this method to use a different test_func method.
        """
        return self.test_func

    def dispatch(self, request, *args, **kwargs):
        test_result = self.get_test_func()()
        if not test_result:
            return redirect(self.get_redirect_url())
        return super().dispatch(request, *args, **kwargs)

The above RedirectMixin class has two important things that make it a mixin, redirect_url which is going to be used by the final view, and test_func which is going to be used by the next specific redirect mixin.

Now create a mixin that uses the above RedirectMixin to redirect authenticated users.

class LoggedInRedirectMixin(RedirectMixin):
    def test_func(self):
        return self.request.user.is_authenticated

Notice, in the above LoggedInRedirectMixin, RedirectMixin is inherited and the test_func() method is overridden.

test_func() is a very important method here, as all the redirect logic is placed inside it.

Now you have created a mixin, which is going to be used in the LoginView you considered initially. Remember!

Note: You can create as many as mixins like LoggedInRedirectMixin based on different conditions, just try to create more generic ones as it's the whole purpose of creating mixins.

Finally, you can use this mixin just by inheriting it.

from django.views.generic import TemplateView

class LoginView(LoggedInRedirectMixin,TemplateView):
    template_name="account/login.html"
    redirect_url = "/some-url/"

Don't forget to add the [redirect_url](https://tech.raturi.in/how-redirect-another-page-django/) attribute in your view. Set it to the URL you want to redirect authenticated users.

You have successfully created a custom mixin. The next section covers a few of the built-in mixins in Django, you can skip 🚀 it if you are here only for custom mixins.

Types of Mixins

In Django, there are two types of mixins: built-in mixins, and custom mixins.

Custom Mixins: These are the mixins created by a user for their specific purpose just like the above LoggedInRedirectMixin.

Built-in Mixins: These are the default mixins that come with Django to provide out-of-the-box functionalities. Here are a list few built-in mixins in Django.

  • LoginRequiredMixin

  • TemplateResponseMixin

  • SingleObjectMixin

  • MultipleObjectMixin

  • FormMixin

You can learn more about built-in class-based mixins in Django from official docs.

Example of Mixins

  • JSONResponseMixin

JSONResponseMixin

Suppose you are writing a set of APIs and each view should return JSON instead of plain HTML. I am taking this code snippet from official Django documentation.

from django.http import JsonResponse

class JSONResponseMixin:
    """
    A mixin that can be used to render a JSON response.
    """
    def render_to_json_response(self, context, **response_kwargs):
        """
        Returns a JSON response, transforming 'context' to make the payload.
        """
        return JsonResponse(
            self.get_data(context),
            **response_kwargs
        )

    def get_data(self, context):
        """
        Returns an object that will be serialized as JSON by json.dumps().
        """
        # Note: This is *EXTREMELY* naive; in reality, you'll need
        # to do much more complex handling to ensure that arbitrary
        # objects -- such as Django model instances or querysets
        # -- can be serialized as JSON.
        return context

Use this mixin in your view like this

from django.views.generic import TemplateView

class JSONView(JSONResponseMixin, TemplateView):
    def render_to_response(self, context, **response_kwargs):
        return self.render_to_json_response(context, **response_kwargs)

More examples will be added in the future in this post.