Rewriting our API using class-based views

We'll start by rewriting the root view as a class-based view. All this involves is a little bit of refactoring of views.py.

  1. from snippets.models import Snippet
  2. from snippets.serializers import SnippetSerializer
  3. from django.http import Http404
  4. from rest_framework.views import APIView
  5. from rest_framework.response import Response
  6. from rest_framework import status
  7. class SnippetList(APIView):
  8. """
  9. List all snippets, or create a new snippet.
  10. """
  11. def get(self, request, format=None):
  12. snippets = Snippet.objects.all()
  13. serializer = SnippetSerializer(snippets, many=True)
  14. return Response(serializer.data)
  15. def post(self, request, format=None):
  16. serializer = SnippetSerializer(data=request.data)
  17. if serializer.is_valid():
  18. serializer.save()
  19. return Response(serializer.data, status=status.HTTP_201_CREATED)
  20. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in views.py.

  1. class SnippetDetail(APIView):
  2. """
  3. Retrieve, update or delete a snippet instance.
  4. """
  5. def get_object(self, pk):
  6. try:
  7. return Snippet.objects.get(pk=pk)
  8. except Snippet.DoesNotExist:
  9. raise Http404
  10. def get(self, request, pk, format=None):
  11. snippet = self.get_object(pk)
  12. serializer = SnippetSerializer(snippet)
  13. return Response(serializer.data)
  14. def put(self, request, pk, format=None):
  15. snippet = self.get_object(pk)
  16. serializer = SnippetSerializer(snippet, data=request.data)
  17. if serializer.is_valid():
  18. serializer.save()
  19. return Response(serializer.data)
  20. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  21. def delete(self, request, pk, format=None):
  22. snippet = self.get_object(pk)
  23. snippet.delete()
  24. return Response(status=status.HTTP_204_NO_CONTENT)

That's looking good. Again, it's still pretty similar to the function based view right now.

We'll also need to refactor our snippets/urls.py slightly now that we're using class-based views.

  1. from django.urls import path
  2. from rest_framework.urlpatterns import format_suffix_patterns
  3. from snippets import views
  4. urlpatterns = [
  5. path('snippets/', views.SnippetList.as_view()),
  6. path('snippets/<int:pk>/', views.SnippetDetail.as_view()),
  7. ]
  8. urlpatterns = format_suffix_patterns(urlpatterns)

Okay, we're done. If you run the development server everything should be working just as before.