There are many options for creating views for your web API, it really depends on what you want and personal preference.
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)
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)
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
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)
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
Routers
Routers in ViewSets allow the URL configuration for your API to be automatically generated using naming standards.
from rest_framework.routers import DefaultRouter from posts.views import PostViewSet router = DefaultRouter() router.register(r'users', UserViewSet) urlpatterns = router.urls
Custom Actions in 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): ... @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/
.