Django REST Framework API Views
Building API endpoints with different view types
👁️ What are API Views?
API Views are the core of DRF endpoints. They handle HTTP requests, process data using serializers, and return responses. DRF offers multiple view types from simple function-based to powerful class-based views.
# Simple function-based view
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET'])
def hello_world(request):
return Response({'message': 'Hello, World!'})
Output:
{
"message": "Hello, World!"
}
View Types
Function Views
Simple decorator-based views
@api_view(['GET', 'POST'])
def book_list(request):
# Handle request
pass
APIView
Class-based view foundation
class BookList(APIView):
def get(self, request):
return Response(data)
Generic Views
Pre-built common patterns
class BookList(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
Mixins
Reusable view behaviors
class BookList(ListModelMixin,
GenericAPIView):
pass
🔹 Function-Based Views
The simplest way to create API endpoints using the @api_view decorator. Perfect for beginners and simple endpoints with straightforward logic:
# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Book
from .serializers import BookSerializer
@api_view(['GET', 'POST'])
def book_list(request):
"""
List all books or create a new book
"""
if request.method == 'GET':
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
elif request.method == 'POST':
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)
@api_view(['GET', 'PUT', 'DELETE'])
def book_detail(request, pk):
"""
Retrieve, update or delete a book
"""
try:
book = Book.objects.get(pk=pk)
except Book.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = BookSerializer(book)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = BookSerializer(book, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
book.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
🔹 APIView Class
Class-based views provide better organization and code reuse. Each HTTP method becomes a separate class method for cleaner structure:
# 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 BookList(APIView):
"""
List all books or create a new book
"""
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)
class BookDetail(APIView):
"""
Retrieve, update or delete a book
"""
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 book is None:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = BookSerializer(book)
return Response(serializer.data)
def put(self, request, pk):
book = self.get_object(pk)
if book is None:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = BookSerializer(book, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
book = self.get_object(pk)
if book is None:
return Response(status=status.HTTP_404_NOT_FOUND)
book.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
# urls.py
from django.urls import path
from .views import BookList, BookDetail
urlpatterns = [
path('books/', BookList.as_view(), name='book-list'),
path('books//', BookDetail.as_view(), name='book-detail'),
]
🔹 Generic Views
Generic views eliminate boilerplate code by providing pre-built implementations for common patterns. Just set queryset and serializer_class:
# views.py
from rest_framework import generics
from .models import Book
from .serializers import BookSerializer
# List and Create
class BookList(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# Retrieve, Update, and Delete
class BookDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
Available Generic Views:
- ListAPIView: Read-only list endpoint
- CreateAPIView: Create-only endpoint
- RetrieveAPIView: Read-only single object
- UpdateAPIView: Update-only endpoint
- DestroyAPIView: Delete-only endpoint
- ListCreateAPIView: List and create
- RetrieveUpdateAPIView: Read and update
- RetrieveDestroyAPIView: Read and delete
- RetrieveUpdateDestroyAPIView: Read, update, delete
🔹 Mixins
Mixins provide reusable behaviors that you can combine to create custom views with specific functionality:
# views.py
from rest_framework import mixins, generics
from .models import Book
from .serializers import BookSerializer
class BookList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class BookDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
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)
Available Mixins:
- ListModelMixin: List queryset
- CreateModelMixin: Create model instance
- RetrieveModelMixin: Retrieve single instance
- UpdateModelMixin: Update instance
- DestroyModelMixin: Delete instance
🔹 Customizing Views
Override methods to add custom behavior to your views:
class BookList(generics.ListCreateAPIView):
serializer_class = BookSerializer
# Custom queryset
def get_queryset(self):
queryset = Book.objects.all()
# Filter by query parameter
author = self.request.query_params.get('author')
if author:
queryset = queryset.filter(author__icontains=author)
return queryset
# Custom create behavior
def perform_create(self, serializer):
# Add current user as owner
serializer.save(owner=self.request.user)
Example Request:
GET /api/books/?author=John
Response:
[
{
"id": 1,
"title": "Python Guide",
"author": "John Doe"
}
]