Django REST Framework Views - API View Creation

Explore various methods for creating Django REST Framework views, from function-based to ViewSets, to build robust APIs. Learn about GET, POST, and custom actions.

Django REST Framework Views

Understanding API View Creation in Django REST Framework

There are many options for creating views for your API, it really depends on your API's requirements or personal preference.

We'll write a post_list view with GET and POST methods for reading and creating new Post instances.

Function-Based Views for APIs

Function-based views offer a straightforward way to handle API requests. They are defined as Python functions that accept a request object and return a response object.

Using Function-based views:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.parsers import JSONParser
from rest_framework import status
from posts.models import Post
from posts.serializers import PostSerializer

@api_view(['GET', 'POST'])
def post_list(request, format=None):

    if request.method == 'GET':
        posts = Post.objects.all()
        serializer = PostSerializer(posts, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = PostSerializer(data=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-Based Views for APIs

Class-based views provide a more object-oriented approach to building APIs, allowing for better organization and reusability of code.

Using Class-based views:

from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from posts.models import Post
from posts.serializers import PostSerializer


class PostList(APIView):
    def get(self, request, format=None):
        snippets = Post.objects.all()
        serializer = PostSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = PostSerializer(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)

Leveraging Generic Class-Based Views

Django REST Framework offers a set of generic views that abstract common patterns, reducing boilerplate code significantly.

Using Generic Class-based views:

from rest_framework import generics
from posts.models import Post
from posts.serializers import PostSerializer


class PostList(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

Building APIs with Mixins

Mixins provide specific actions that can be combined with generic views to create more specialized functionality.

Using Mixins:

from rest_framework import generics, mixins
from posts.models import Post
from posts.serializers import PostSerializer


class PostList(generics.GenericAPIView,
               mixins.ListModelMixin,
               mixins.CreateModelMixin
               ):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

Efficient API Management with ViewSets

ViewSets consolidate logic for multiple related views into a single class, simplifying URL routing and code management.

Using ViewSets:

With ModelViewSet (in this case), you don't have to create separate views for getting list of objects and detail of one object. ViewSet will handle it for you in a consistent way for both methods.

from rest_framework import viewsets
from posts.models import Post
from posts.serializers import PostSerializer


class PostViewSet(viewsets.ModelViewSet):
    """
    A viewset for viewing and editing post instances.
    """
    queryset = Post.objects.all()
    serializer_class = PostSerializer

So basically, this would not only generate the list view, but also the detail view for every Post instance.

Routers for Automatic URL Configuration

Routers in ViewSets allow the URL configuration for your API to be automatically generated using naming standards, which is highly efficient.

from rest_framework.routers import DefaultRouter
from posts.views import PostViewSet

router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls

Adding Custom Actions to ViewSets

DRF provides helpers to add custom actions for ad-hoc behaviours with the @action decorator. The router will configure its url accordingly. For example, we can add a comments action in the our PostViewSet to retrieve all the comments of a specific post as follows:

from rest_framework import viewsets
from rest_framework.decorators import action
from posts.models import Post
from posts.serializers import PostSerializer, CommentSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

    @action(methods=['get'], detail=True)
    def comments(self, request, pk=None):
        try:
            post = Post.objects.get(id=pk)
        except Post.DoesNotExist:
            return Response({"error": "Post not found."},
                            status=status.HTTP_400_BAD_REQUEST)
        comments = post.comments.all()
        return Response(CommentSerializer(comments, many=True))

Upon registering the view as router.register(r'posts', PostViewSet), this action will then be available at the url posts/{pk}/comments/.

Back to Top ↑