SyntaxStudy
Sign Up
Django APIView and Generic Views in DRF
Django Beginner 1 min read

APIView and Generic Views in DRF

DRF provides several levels of abstraction for writing API views. APIView is the lowest level — it works like a CBV but adds DRF's content negotiation, authentication, and permission checking. You define get(), post(), put(), patch(), and delete() methods. APIView gives you full control but requires the most boilerplate code for listing and creating resources. Generic views (ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView, and combination views like ListCreateAPIView and RetrieveUpdateDestroyAPIView) implement the standard CRUD patterns with minimal code. You set the queryset, serializer_class, and optionally permission_classes and authentication_classes attributes. Most customisation is done by overriding small hook methods like get_queryset() or perform_create(). The perform_create() and perform_update() hooks are the right place to inject request data before saving — for example setting the author to request.user before creating a post. This keeps the serializer clean (it doesn't need to know about the request) while letting the view control how objects are saved. The get_serializer_context() method passes the request to the serializer so serializer methods can build absolute URLs.
Example
# blog/api/views.py — APIView and generic views
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, generics, permissions
from ..models import Post
from ..serializers import PostSerializer


# --- Low-level APIView ---
class PostListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def get(self, request):
        posts = Post.published.select_related('author').order_by('-published_at')
        serializer = PostSerializer(posts, many=True, context={'request': request})
        return Response(serializer.data)

    def post(self, request):
        serializer = PostSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            serializer.save(author=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


# --- Generic views (preferred) ---
class PostListCreateView(generics.ListCreateAPIView):
    queryset           = Post.published.select_related('author')
    serializer_class   = PostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)


class PostRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
    queryset           = Post.published.all()
    serializer_class   = PostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def perform_update(self, serializer):
        serializer.save(author=self.request.user)