06 类视图

APIView

基于类的视图编写API视图,允许我们重用常用的功能。

基于类视图重写API

  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. 列出所有的snippets或者创建一个新的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)
  21. class SnippetDetail(APIView):
  22. """
  23. 检索,更新或删除一个snippet示例。
  24. """
  25. def get_object(self, pk):
  26. try:
  27. return Snippet.objects.get(pk=pk)
  28. except Snippet.DoesNotExist:
  29. raise Http404
  30. def get(self, request, pk, format=None):
  31. snippet = self.get_object(pk)
  32. serializer = SnippetSerializer(snippet)
  33. return Response(serializer.data)
  34. def put(self, request, pk, format=None):
  35. snippet = self.get_object(pk)
  36. serializer = SnippetSerializer(snippet, data=request.data)
  37. if serializer.is_valid():
  38. serializer.save()
  39. return Response(serializer.data)
  40. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  41. def delete(self, request, pk, format=None):
  42. snippet = self.get_object(pk)
  43. snippet.delete()
  44. return Response(status=status.HTTP_204_NO_CONTENT)

ViewSets

REST框架包含一个用于处理的抽象概念 ViewSets,它允许开发人员专注于对API的状态和交互进行建模,并根据通过约定自动处理URL构造。

  1. viewsets = (view1, view2, view3, viewN...)

DRF允许您将一组相关的视图view逻辑的组合到一个类中,称为一个ViewSet

  • ViewSet类与View类几乎相同
  • 它不提供任何方法处理程序,如(get/post/),而是提供诸如(list/create/read/update)
  • 一个ViewSet类只在最后时刻绑定到一组方法处理程序,当它被实例为一组视图时,通常通过使用一个Router类来处理复杂的URL conf

使用ViewSet重构

UserListUserDetail观点重构成一个单一的UserViewSet。我们可以删除这两个视图,并用一个类来替换它们。

  1. from rest_framework import viewsets
  2. class UserViewSet(viewsets.ReadOnlyModelViewSet):
  3. """
  4. 此视图集自动提供‘list’和‘detail’操作
  5. """
  6. queryset = User.objects.all()
  7. serializer_class = UserSerializer

ReadOnlyModelViewSet自动提供默认的“只读”操作。

SnippetList,SnippetDetail和SnippetHighlight视图类更换为一个SnippetViewSet

  1. from rest_framework.decorators import action
  2. from rest_framework.response import Response
  3. class SnippetViewSet(viewsets.ModelViewSet):
  4. """
  5. 此视图集自动提供“list”、“create”、“retrieve”、“update”和“destroy”操作
  6. """
  7. queryset = Snippet.objects.all()
  8. serializer_class = SnippetSerializer
  9. permission_classes = (permissions.IsAuthenticatedOrReadOnly,
  10. IsOwnerOrReadOnly,)
  11. @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
  12. def highlight(self, request, *args, **kwargs):
  13. snippet = self.get_object()
  14. return Response(snippet.highlighted)
  15. def permform_create(self, serializer):
  16. serializer.save(owner=self.request.user)

继承自ModelViewSet类,提供完整的读写操作。

  • @action装饰自定义操作highlight。用来添加任何不符合标准create/update/delete的自定义endpoints
  • @action默认处理GET请求,如果要处理POST请求,可以使用method参数来指定

view与viewsets之间权衡

viewsets是一个非常有用的抽象

  • 有助于确保URL在API中保持一致,最大限度地减少需要编写的代码量
  • 使用viewsets时,不如view更明确。