Django REST Framework (DRF) provides several ways to build APIs. Among the most foundational and flexible options is the APIView
class. It’s perfect for developers who want full control over request handling without giving up DRF’s helpful features like parsing, rendering, and authentication.
In this guide, we’ll explore:
-
What
APIView
is and why it’s used -
How it differs from Django views and DRF’s
ViewSet
-
Step-by-step implementation
-
Example with GET and POST methods
-
Tips, best practices, and common mistakes
What is APIView
?
APIView
is a class-based view provided by DRF that inherits from Django’s View
but adds REST-specific functionality like:
-
Content negotiation (JSON, XML, etc.)
-
Request/response objects
-
Authentication and permissions
-
Exception handling
In short: it’s like Django’s View
, but built for APIs.
When to Use APIView
Use APIView
when:
-
You want full control over the request methods (
GET
,POST
,PUT
,DELETE
) -
You want to handle logic manually (vs. automatic CRUD with
ModelViewSet
) -
You need fine-grained control over authentication, permissions, and data
Basic Structure of APIView
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class HelloWorldView(APIView):
def get(self, request):
return Response({"message": "Hello, world!"})
def post(self, request):
data = request.data
return Response({"you_sent": data}, status=status.HTTP_201_CREATED)
Real-World Example: Book API
Assume we have a simple Book
model:
# models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
Create a Serializer:
# serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title', 'author']
APIView for List and Create:
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Book
from .serializers import BookSerializer
class BookListCreateAPIView(APIView):
def get(self, request):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
def post(self, request):
serializer = BookSerializer(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)
APIView for Retrieve, Update, and Delete
class BookDetailAPIView(APIView):
def get_object(self, pk):
try:
return Book.objects.get(pk=pk)
except Book.DoesNotExist:
return None
def get(self, request, pk):
book = self.get_object(pk)
if not book:
return Response({"error": "Not found"}, status=404)
serializer = BookSerializer(book)
return Response(serializer.data)
def put(self, request, pk):
book = self.get_object(pk)
if not book:
return Response({"error": "Not found"}, status=404)
serializer = BookSerializer(book, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400)
def delete(self, request, pk):
book = self.get_object(pk)
if not book:
return Response({"error": "Not found"}, status=404)
book.delete()
return Response(status=204)
URLs Setup
# urls.py
from django.urls import path
from .views import BookListCreateAPIView, BookDetailAPIView
urlpatterns = [
path('books/', BookListCreateAPIView.as_view()),
path('books/<int:pk>/', BookDetailAPIView.as_view()),
]
✅ Benefits of APIView
-
Fine-grained control over HTTP methods
-
Explicit and easy to debug
-
Built-in support for DRF’s powerful features: authentication, permissions, throttling, etc.
-
Great for building custom APIs that don’t match standard CRUD
⚠️ Common Mistakes
Mistake | Solution |
---|---|
Not calling .as_view() in URLs |
Always use .as_view() when adding to urlpatterns |
Forgetting to return Response |
Always return DRF’s Response , not Django’s HttpResponse |
Not handling 404 manually | Use helper methods (get_object_or_404 ) or handle exceptions |
Mixing Django forms with DRF serializers | Stick to DRF serializers for API logic |
Tips and Best Practices
-
✅ Use
APIView
when you need custom logic per method. -
✅ Prefer
ViewSet
orModelViewSet
for standard CRUD operations. -
✅ Use mixins (
ListModelMixin
,CreateModelMixin
, etc.) withGenericAPIView
to avoid boilerplate. -
✅ Use
Response()
from DRF for proper content negotiation. -
✅ Leverage
status
module for readable HTTP codes.
Final Thoughts
APIView
is your go-to tool in DRF when you want full control without sacrificing the power of Django’s robust backend and DRF’s API features. It's the perfect blend of customizability and structure — great for custom business logic, authentication flows, and non-standard endpoints.
If you want to go further, look into:
-
GenericAPIView
and mixins -
ViewSet
vsAPIView
-
Adding authentication/permissions to
APIView