Django: How to Write Your Own Custom ViewSet Class (With Examples)

Last updated 4 months ago | 310 views 75     5

Tags:- Python Django DRF

Introduction: Why Write Your Own ViewSet?

Django Rest Framework (DRF) provides powerful generic ViewSet classes like ModelViewSet and ReadOnlyModelViewSet. These work great for CRUD operations out-of-the-box, but what if you need fine-grained control over your views?

Creating your own custom ViewSet lets you:

  • Define precise behavior for each HTTP method

  • Add custom authentication, throttling, or permissions

  • Avoid bloated logic in generic views

  • Improve performance by customizing database access

This article walks you through how to build your own ViewSet from scratch, with practical examples and tips.


Understanding the Basics of a ViewSet

A ViewSet in DRF is a class that combines logic for a set of related views. Instead of writing separate APIView classes for each action (like list, create, retrieve), a ViewSet groups them together.

Here's what Django Rest Framework provides:

Built-in ViewSet Inherits From Provides
ViewSet APIView No default actions
GenericViewSet ViewSet + mixins Basic behavior for CRUD
ModelViewSet GenericViewSet + CRUD mixins Full CRUD out-of-the-box

When you write your own ViewSet, you typically subclass ViewSet or GenericViewSet and implement the methods manually.


Step-by-Step: Writing a Custom ViewSet Class

1. Create a Serializer

First, define a serializer for your model:

# serializers.py
from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'created_at']

2. Write a Custom ViewSet Class

Let’s build a CustomArticleViewSet that supports list, retrieve, and create operations.

# views.py
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework import status
from .models import Article
from .serializers import ArticleSerializer
from django.shortcuts import get_object_or_404

class CustomArticleViewSet(ViewSet):
    """
    A custom ViewSet for listing, retrieving, and creating articles.
    """

    def list(self, request):
        # GET /articles/
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        # GET /articles/<pk>/
        article = get_object_or_404(Article, pk=pk)
        serializer = ArticleSerializer(article)
        return Response(serializer.data)

    def create(self, request):
        # POST /articles/
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

3. Register the ViewSet with a Router

# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CustomArticleViewSet

router = DefaultRouter()
router.register(r'articles', CustomArticleViewSet, basename='article')

urlpatterns = [
    path('', include(router.urls)),
]

✅ Full Working Example

Let’s put everything together.

models.py

from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

serializers.py

from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

views.py

from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework import status
from .models import Article
from .serializers import ArticleSerializer
from django.shortcuts import get_object_or_404

class CustomArticleViewSet(ViewSet):
    def list(self, request):
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        article = get_object_or_404(Article, pk=pk)
        serializer = ArticleSerializer(article)
        return Response(serializer.data)

    def create(self, request):
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

urls.py

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CustomArticleViewSet

router = DefaultRouter()
router.register(r'articles', CustomArticleViewSet, basename='article')

urlpatterns = [
    path('', include(router.urls)),
]

Tips & Common Pitfalls

✅ Best Practices

  • Always use get_object_or_404() for safety in retrieve, update, and destroy.

  • Keep each method short and readable.

  • Use basename when registering a custom ViewSet to avoid router errors.

  • Override only the methods you need (e.g., update, partial_update, destroy).

⚠️ Common Pitfalls

  • Forgetting basename in router registration when queryset is not defined.

  • Mixing concerns — don't put business logic inside the ViewSet; keep it clean.

  • Missing serializer validation before saving.

  • Skipping authentication/permissions — always secure your endpoints!


When Should You Write a Custom ViewSet?

Use Case Recommended Approach
Standard CRUD (Create/Read/Update/Delete) Use ModelViewSet
Custom logic in some actions Subclass GenericViewSet + override specific methods
Fully custom behavior or non-model views Use ViewSet from scratch

Summary and Best Practices

Creating your own custom ViewSet in Django gives you full control over how each HTTP method behaves. It's ideal when:

  • You need custom business logic per action.

  • You want lightweight views without generic mixins.

  • You aim to build clean, maintainable APIs.

Start with ModelViewSet when possible, but don’t be afraid to roll up your sleeves and write your own ViewSet when customization calls for it.


Final Thoughts

Custom ViewSets are a powerful tool in your Django REST toolbox. Once you master them, you'll be able to build APIs that are not just functional, but tailored, secure, and elegant.

Ready to build smarter APIs? Start writing your own ViewSet today.