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

  • 相关阅读:
    hdu5728 PowMod
    CF1156E Special Segments of Permutation
    CF1182E Product Oriented Recurrence
    CF1082E Increasing Frequency
    CF623B Array GCD
    CF1168B Good Triple
    CF1175E Minimal Segment Cover
    php 正则
    windows 下安装composer
    windows apache "The requested operation has failed" 启动失败
  • 原文地址:https://www.cnblogs.com/9527mwz/p/11200592.html
Copyright © 2011-2022 走看看