Backend Development 12 min read

Using Mixins in Django REST Framework to Extend View Functionality

This article explains how to use Django REST Framework mixins to extend view functionality, providing step‑by‑step code examples for list, retrieve, create, update, delete, custom authentication, permissions, versioning, conditional rendering, and custom exception handling.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Using Mixins in Django REST Framework to Extend View Functionality

In Django REST Framework (DRF), mixins are a common design pattern for extending view functionality. By inheriting from mixin classes you can compose reusable behaviors for ViewSets and generic views.

Example: Using ListModelMixin and RetrieveModelMixin

from rest_framework import mixins
from rest_framework import generics
from django.contrib.auth.models import User
from .serializers import UserSerializer
class UserListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.RetrieveModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def get(self, request, *args, **kwargs):
        if 'pk' in kwargs:  # detailed view
            return self.retrieve(request, *args, **kwargs)
        else:  # list view
            return self.list(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserListView
urlpatterns = [
    path('users/', UserListView.as_view(), name='user_list'),
    path('users/
/', UserListView.as_view(), name='user_detail'),
]

Example: Using CreateModelMixin and UpdateModelMixin

from rest_framework import mixins
from rest_framework import generics
from django.contrib.auth.models import User
from .serializers import UserSerializer
class UserCRUDView(generics.GenericAPIView, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserCRUDView
urlpatterns = [
    path('users/', UserCRUDView.as_view(), name='user_create'),
    path('users/
/', UserCRUDView.as_view(), name='user_update_delete'),
]

Example: Combining ListModelMixin and CreateModelMixin

from rest_framework import mixins
from rest_framework import generics
from django.contrib.auth.models import User
from .serializers import UserSerializer
class UserListCreateView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserListCreateView
urlpatterns = [
    path('users/', UserListCreateView.as_view(), name='user_list_create'),
]

Example: RetrieveModelMixin and UpdateModelMixin

from rest_framework import mixins
from rest_framework import generics
from django.contrib.auth.models import User
from .serializers import UserSerializer
class UserDetailUpdateView(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserDetailUpdateView
urlpatterns = [
    path('users/
/', UserDetailUpdateView.as_view(), name='user_detail_update'),
]

Example: Using DestroyModelMixin

from rest_framework import mixins
from rest_framework import generics
from django.contrib.auth.models import User
from .serializers import UserSerializer
class UserDeleteView(generics.GenericAPIView, mixins.DestroyModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserDeleteView
urlpatterns = [
    path('users/
/', UserDeleteView.as_view(), name='user_delete'),
]

These examples demonstrate how DRF mixin classes can be combined to quickly build views with the desired capabilities, improving code readability and maintainability.

Advanced Example: Custom Authentication and Permission

from django.contrib.auth.models import User
from rest_framework import mixins, generics, authentication, permissions
from .serializers import UserSerializer
# Custom authentication backend
class CustomAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        # Implement custom token extraction and validation here
        return None
# Custom permission class
class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj == request.user
class UserDetailView(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    authentication_classes = [CustomAuthentication]
    permission_classes = [IsOwnerOrReadOnly]
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserDetailView
urlpatterns = [
    path('users/
/', UserDetailView.as_view(), name='user_detail'),
]

Versioning

from rest_framework import mixins, generics, versioning
from .serializers import UserSerializer
class UserListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    versioning_class = versioning.URLPathVersioning
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
# URL configuration
from django.urls import path, re_path
from .views import UserListView
urlpatterns = [
    re_path(r'^users/v(?P
[1-9])/$', UserListView.as_view(), name='user_list'),
]

Conditional Rendering

from rest_framework import mixins, generics, renderers
from .serializers import UserSerializer
class UserListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    renderer_classes = [renderers.JSONRenderer, renderers.XMLRenderer]
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserListView
urlpatterns = [
    path('users/', UserListView.as_view(), name='user_list'),
]

Custom Exception Handling

from django.http import JsonResponse
from rest_framework import status
from rest_framework.exceptions import APIException
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is not None:
        response.data['status_code'] = response.status_code
    return response
class CustomAPIException(APIException):
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    default_detail = 'An unexpected error occurred.'
    default_code = 'unexpected_error'
class UserListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def get(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            raise CustomAPIException(detail='You need to log in to access this resource.')
        return self.list(request, *args, **kwargs)
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserListView
urlpatterns = [
    path('users/', UserListView.as_view(), name='user_list'),
]

Complex Logic with APIView and Mixins

from rest_framework import mixins, generics, status
from rest_framework.response import Response
from .serializers import UserSerializer
class UserManagementView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def get(self, request, *args, **kwargs):
        if 'pk' in kwargs:
            return self.retrieve(request, *args, **kwargs)
        return self.list(request, *args, **kwargs)
    def post(self, request, *args, **kwargs):
        if 'pk' in kwargs:
            return self.partial_update(request, *args, **kwargs)
        return self.create(request, *args, **kwargs)
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
# URL configuration
from django.urls import path
from .views import UserManagementView
urlpatterns = [
    path('users/', UserManagementView.as_view(), name='user_management'),
    path('users/
/', UserManagementView.as_view(), name='user_management_detail'),
]

These examples show how to leverage DRF mixins for advanced features such as custom authentication, permission checks, API versioning, content negotiation, custom error handling, and complex view logic, enabling developers to build efficient and maintainable APIs.

DjangoAPIDRFMixin
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.