zoukankan      html  css  js  c++  java
  • 视图组件

    视图组件

    基本视图

    路由

        url(r'^publish/$', views.PublishView.as_view()),
        url(r'^publish/(?P<pk>d+)/',views.PublishDetailView.as_view()),
    

    serializer.py

    from app01 import models
    class PublishSerializers(serializers.ModelSerializer):
        class Meta:
            model=models.Publish
            fields='__all__'
    

    view.py

    class PublishView(APIView):
    
        def get(self, request):
            publish_list = models.Publish.objects.all()
            bs = PublishSerializers(publish_list, many=True)
            # 序列化数据
    
            return Response(bs.data)
    
        def post(self, request):
            # 添加一条数据
            print(request.data)
    
            bs=PublishSerializers(data=request.data)
            if bs.is_valid():
                bs.save()  # 生成记录
                return Response(bs.data)
            else:
    
                return Response(bs.errors)
    
    class PublishDetailView(APIView):
        def get(self,request,pk):
            publish_obj=models.Publish.objects.filter(pk=pk).first()
            bs=PublishSerializers(publish_obj,many=False)
            return Response(bs.data)
        def put(self,request,pk):
            publish_obj = models.Publish.objects.filter(pk=pk).first()
    
            bs=PublishSerializers(data=request.data,instance=publish_obj)
            if bs.is_valid():
                bs.save() # update
                return Response(bs.data)
            else:
                return Response(bs.errors)
        def delete(self,request,pk):
            models.Publish.objects.filter(pk=pk).delete()
    
            return Response("")
    

    mixin类和generice类编写视图

    ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

    五个类中封装了查所有、新创 | 查一个、更新、删除 五种方法

    但是在这五个方法中用到的get_serializer、get_object等方法均在GenericAPIView类中

    而GenericAPIView类需要queryset或者serializer_class参数

    因此我们只需要让视图类继承上述五个类和GenericAPIView类组合即可实现简单的增删改查的接口

    views.py

    from rest_framework.mixins import CreateModelMixin,RetrieveModelMixin,ListModelMixin,UpdateModelMixin,DestroyModelMixin
    from rest_framework.generics import GenericAPIView
    class PublishView(ListModelMixin,CreateModelMixin,GenericAPIView):
        queryset=models.Publish.objects.all()
        serializer_class=PublishSerializers
    
        def get(self, request):
            return self.list(request)
    
        def post(self, request):
            return self.create(request)
    
    class PublishDetailView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
        queryset=models.Publish.objects.all()
        serializer_class=PublishSerializers
        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)
    

     这个时候,我们只需要提供queryset和serializer_class两个参数配置,mixin包下面的类会帮我们处理数据,我们调用对应的方法并且将其返回值返回即可,

    但是需要注意的是,如果使用此方法,urls.py的url对应的id要命名为pk,如下:

    url(r'^publishes/$', views.PublishView.as_view()),
    url(r'^publishes/(?P<pk>d+)/$', views.PublishDetailView.as_view()),
    

    但是,即使我们用了这种封装,很多代码还是有重复的,所有,rest_framework又给我们做了一层封装

    使用generics 下ListCreateAPIView,RetrieveUpdateDestroyAPIView

    ListCreateAPIView类

    继承了ListModelMixin,CreateModelMixin和GenericAPIView

    在类体代码中实现了get 和 post 方法 并返回了序列化结果

    RetrieveUpdateDestroyAPIView类

    继承了RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin和GenericAPIView

    在类体代码中实现了get 、 (put、patch)、delete方法 并返回了序列化结果

    所以有如下写法

    from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
    class PublishView(ListCreateAPIView):
        queryset=models.Publish.objects.all()
        serializer_class=PublishSerializers
    
    class PublishDetailView(RetrieveUpdateDestroyAPIView):
        queryset=models.Publish.objects.all()
        serializer_class=PublishSerializers
    

    这样,代码就清晰很多了,但是,这种方法依然是将一个model表分成两个视图,那,有没有一种方法能将他们合并在一起呢?

    使用ModelViewSet

    路由:

        url(r'^publish/$', views.PublishView.as_view({'get':'list','post':'create'})),
        url(r'^publish/(?P<pk>d+)/$', views.PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
    

    views.py

    from rest_framework.viewsets import ModelViewSet
    class PublishView(ModelViewSet):
        queryset=models.Publish.objects.all()
        serializer_class=PublishSerializers
    

    自定义方法与不同请求方式对应

    url.py

        url(r'^aa/$', views.PublishView.as_view({'get': 'aaa'})),
        url(r'^bb/$', views.PublishView.as_view({'get': 'bbb'})),
    

    views.py

    from rest_framework.viewsets import  ViewSetMixin
    from rest_framework.views import  APIView
    # ViewSetMixin 重写了as_view方法
    class Test(ViewSetMixin,APIView):
    
        def aaa(self,request):
            return Response()
    	def bbb(self,request):
    		return Response()
    

    源码分析

    普通的CBV中的视图类as_view()是无法传参的,ViewSetMixin 重写了as_view方法

    rest_framework>viewsets>ViewSetMixin

    部分源码如下:

    @classonlymethod
        def as_view(cls, actions=None, **initkwargs):
            """
            Because of the way class based views create a closure around the
            instantiated view, we need to totally reimplement `.as_view`,
            and slightly modify the view function that is created and returned.
            """
           ......
        # 若继承了ModelViewSet类必须在路由中传入actions
            if not actions:
                raise TypeError("The `actions` argument must be provided when "
                                "calling `.as_view()` on a ViewSet. For example "
                                "`.as_view({'get': 'list'})`")
    
         ......
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                # We also store the mapping of request methods to actions,
                # so that we can later set the action attribute.
                # eg. `self.action = 'list'` on an incoming GET request.
                self.action_map = actions
    
                # Bind methods to actions
                # This is the bit that's different to a standard view
                # 将视图类中的action方法与请求方式绑定 
                # 不同的请求方式对应出发不同的方法
                for method, action in actions.items():
                    handler = getattr(self, action)
                    setattr(self, method, handler)
    			# 请求头相关的
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
    
                self.request = request
                self.args = args
                self.kwargs = kwargs
    
                # And continue as usual
                return self.dispatch(request, *args, **kwargs)
    

    主键中各个类的继承关系

    各个类关系分析

    首先我们得了解一下,当我们不去自己继承View类定义类视图时,DRF给哦们提供了几个继承自View类的丰富的类

    基类:APIView

    APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

    APIViewView的不同之处在于:

    传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
    视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
    任何APIException异常都会被捕获到,并且处理成合适的响应信息;
    在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
    支持定义的属性:

    authentication_classes 列表或元祖,身份认证类
    permissoin_classes 列表或元祖,权限检查类

    throttle_classes 列表或元祖,流量控制类

    APIView中仍和普通的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

    2.基类:GenericAPIView

    提供的关于序列化器使用的属性与方法

    GenericAPIView
    继承自APⅣew,主要增加了操作序列化器和数
    据库查询的方法,作用是为下面Mixn扩展类的
    执行提供方法支持。通常在使用时,可搭配一个
    或多个Min扩展类
    指明视图使用的序列化器
    1通过属性: serializer_ class
    2通过方法: get serializer_class(self
    get serializer(self, args, * kwargs)
    数据库查询的属性与方法
    指明使用的数据查询集
    1通过属性: queryset
    2通过方法: get queryset(se)
    get object(self)

    配合GenericAPIView使用的几个扩展类

    我们发现前边的两个父类还需要进行函数的定义去处理不同的请求,这样我们还得在函数里边实现查询集以及序列化器的指定,工作量仍然很大。怎么解决呢?

    GenericAPIView的五个扩展类给我们提供了五个方法分别进行增删改查的不同操作,这样我们就不用写那么多函数啦!!

    搭配GenericAPIView使用

    1.ListModelMixin: 提供list方法快速实现列表视图

    2.CreateModelMixin: 提供create方法快速实现创建资源的视图

    3.RetrieveModelMixin 提供retrieve方法,可以快速实现返回一个存在的数据对象(需要传入pk)

    4.UpdateModelMixin 提供update方法,可以快速实现更新一个存在的数据对象。 提供partial_update方法,可以实现局部更新

    5.DestroyModelMixin 提供destroy方法,可以快速实现删除一个存在的数据对象

    1.CreateAPIView(等价于GenericAPIView+CreateModelMixin) 提供 post 方法 继承自: GenericAPIView、CreateModelMixin

    2.ListAPIView 提供 get 方法 继承自:GenericAPIView、ListModelMixin

    3.RetrieveAPIView 提供 get 方法 继承自: GenericAPIView、RetrieveModelMixin

    4.DestoryAPIView 提供 delete 方法 继承自:GenericAPIView、DestoryModelMixin

    5.UpdateAPIView 提供 put 和 patch 方法 继承自:GenericAPIView、UpdateModelMixin

    6.RetrieveUpdateAPIView 提供 get、put、patch方法 继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

    7.RetrieveUpdateDestoryAPIView 提供 get、put、patch、delete方法 继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

    所以代码中的mixins.RetrieveModelMixin, GenericAPIView可以写成RetrieveAPIView

  • 相关阅读:
    Nginx URL后面不加斜杠301重定向
    Jenkins 配置 Node.js 项目
    在 Linux 上搭建IntelliJ IDEA license server服务器
    Vue 使用细节收集
    sinopia 搭建记录
    cli 开发记录
    Cgroup(一)简介
    Kubernetes (一)POD驱逐
    RabbitMQ(五)镜像队列
    RabbitMQ(四)队列结构
  • 原文地址:https://www.cnblogs.com/9527mwz/p/11200592.html
Copyright © 2011-2022 走看看