Django-Rest-Framework 教程: 3. 使用 class based views

在我们的博客中, 记录了我们在开发过程中所使用的技术和遇到的问题, 希望作为其他开发和设计者的一个学习交流平台.

Django-Rest-Framework 教程: 3. 使用 class based views


在上一篇Django-Rest-Framework 教程: 2. Requests 和 Responses中, 使用的是function based views. 在本篇中, 主要介绍怎样使用class based views.

1. 修改views.py

首先修改snippet_list view:

    # snippets/views.py
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from django.http import Http404
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status


    class SnippetList(APIView):
        """
        展示所有存在的snippet, 或建立新的snippet
        """
        def get(self, request, format=None):
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)
            return Response(serializer.data)

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

使用class based view代替 snippet_list后, 两者的代码非常相似, 但对于不同Http动作, 分离效果更为优秀. 对于snippet_detail:

    # snippets/views.py
    class SnippetDetail(APIView):
        """
        展示, 更新或删除一个snippet
        """
        def get_object(self, pk):
            try:
                return Snippet.objects.get(pk=pk)
            except Snippet.DoesNotExist:
                raise Http404

        def get(self, request, pk, format=None):
            snippet = self.get_object(pk)
            serializer = SnippetSerializer(snippet)
            return Response(serializer.data)

        def put(self, request, pk, format=None):
            snippet = self.get_object(pk)
            serializer = SnippetSerializer(snippet, data=request.DATA)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        def delete(self, request, pk, format=None):
            snippet = self.get_object(pk)
            snippet.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)

更新urls.py:

    # snippets/urls.py
    from django.conf.urls import patterns, url
    from rest_framework.urlpatterns import format_suffix_patterns
    from snippets import views

    urlpatterns = patterns('',
        url(r'^snippets/$', views.SnippetList.as_view()),
        url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
    )

    urlpatterns = format_suffix_patterns(urlpatterns)

class based view改造完成, 现在可以使用之前的测试方法进行测试了.

2. 使用 Mixins

使用class based views的一大好处是, 我们可以使用各种mixin.

Django-rest-framework为我们提供了许多现成的mixins, 方便我们像使用model-backed API一样构建 "创建/获取/更新/删除" API. 我们试着使用Mixins改写原先的view.

GenericAPIView为我们提供了view核心的功能, 而ListModelMixin和CreateModelMixin为我们提供了.list()和.create()功能. 我们将这些功能与http动作绑定:

    # snippets/views.py
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from rest_framework import mixins
    from rest_framework import generics

    class SnippetList(mixins.ListModelMixin,
                      mixins.CreateModelMixin,
                      generics.GenericAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer

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

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

同样的, 我们使用GenericAPIView, RetrieveModelMixin, UpdateModelMixin和DestroyModelMixin改写views.py:

    # snippets/views.py
    class SnippetDetail(mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        generics.GenericAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer

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

        def put(self, request, *args, **kwargs):
            return self.update(request, *args, **kwargs)

        def delete(self, request, *args, **kwargs):
            return self.destroy(request, *args, **kwargs)

3. 使用generic class based views

同Django一样, django-rest-framework为我们提供了现成的generic class based views. 接下来我们使用这些GCBVs再一次修改原有的views.py:

    # snippets/views.py
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from rest_framework import generics


    class SnippetList(generics.ListCreateAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer


    class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer

可以发现, 使用GCBVs后, 代码变得的更为精简易懂.


原文链接: http://weiguda.com/blog/21/