在API视图的编写方法上,DRF为我们提供了很多种选择,比如基于类的视图。这是一个强大的 模式,允许我们重用常用的功能,并帮助我们保持代码的DRY特性。

一、使用基于类的视图重写我们的API

我们又将再一次重写 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):
    """
    列表  创建
    """

    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(instance=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)

注意类视图的名字规范,和基于函数的视图是不一样的,所以这里换了名字。

在原生的Django中编写类视图是这样的:

from django.http import HttpResponse
from django.views import View


class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')

    def post(self, request):
        # <view logic>
        return HttpResponse('something')

比较一下区别,最主要的是我们导入了这个类:from rest_framework.views import APIView,在自己写的视图类中继承它。那么这个APIView是什么呢?它是DRF对Django.view.View类的高级封装,添加了很多DRF需要使用的特性,比如可浏览的API页面等。

当然,我们还需要更新 views.py 中的detail实例视图。

class SnippetDetail(APIView):
    """
    获取 更新 删除
    """

    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(instance=snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(instance=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)

看起来不错,但它现在仍然非常类似于基于函数的视图。(其实就是拆分了逻辑,实现可重用)

接下来,我们还需要重构我们的 snippets.urls.py ,因为Django对类视图有专门的url编写 格式,不得不改:

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
    path('snippets/', views.SnippetList.as_view()),
    path('snippets/<int:pk>/', views.SnippetDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)

好了,阶段完成,如果你重新启动服务器,那么它应该像之前一样运行。


二、使用混合类(mixins)

等等,你以为DRF的视图体系到此就完了吗?你想得太简单了!一大波内容还在后面..... 使用基于类的视图,最大优势之一是创建可复用的代码。

到目前为止,我们使用的创建/获取/更新/删除操作中有一部分代码是非常类似的,完全可以抽 象出来。DRF就这么干了,并把这部分代码放到mixin类系列中,然后作为父类供子类继承复 用。

让我们来看看我们是如何通过使用mixin类编写视图的。打开 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)

我们分析下这里的具体实现方式。我们自己写的SnippetList类继承了三个类,其中两个是mixin类,最后是GenericAPIView类,GenericAPIView类作为结构主父类,提供了基本的DRF的API类视图功能,GenericAPIView类直接继承了我们前面使用的APIView类。而ListModelMixinCreateModelMixin提供.list().create()操作。

另外强调一点Python多继承的特点,继承父类的先后位置关系是有意义的,不可以随意调 换顺序。

然后我们明确地将 getpost 方法绑定到适当的操作。

再修改一下我们的Detail类:

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)

和上面的那个类非常相似。

三、使用通用的基于类的视图

看完上面的内容,感觉又get到了新知识!以后就这么干了!

等等,DRF实际上又帮我们抽象了上面的代码,提供了一些通用的类似的类视图。WTF, 那你前面还跟我啰嗦那么多?直接使用下面的方法就好了啊!

通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提 供了一组已经混合好(mixed-in)的通用的类视图,我们可以使用它来简化我们的 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

你所需要做的,只是继承 generics 模块中的现成的某个通用类视图,比如 ListCreateAPIView 。然后在类里定义 querysetserializer_class 两个属性的值,剩下的什么都不用写,全部交给DRF,它会帮你搞定。

本文作者:博主:
文章标题:DRF-快速入门--基于类的视图
本文地址:https://wouldmissyou.com/archives/42/     
版权说明:若无注明,本文皆为“多点部落”原创,转载请保留文章出处。
最后修改:2021 年 01 月 20 日 09 : 07 AM
如果觉得我的文章对你有用,请随意赞赏