zoukankan      html  css  js  c++  java
  • drf5

    复习

    """
    1、整体修改与局部修改
    	# 序列化
    	ser_obj = ModelSerializer(model_obj)  
    	# 反序列化,save() => create()
    	ser_obj = ModelSerializer(data=model_data)  
    	# save() => update()
    	ser_obj = ModelSerializer(instance=model_obj,data=model_data)  
    	# partial=True => 匹配字段required=True校验条件
    	ser_obj = ModelSerializer(instance=model_obj,data=model_data,partial=True)
    	
    
    2、群改ListSerializer
    	ser_obj = ModelSerializer(instance=model_obj,data=model_data,partial=True,many=True)
    	
    	# 一旦设置了many=True,反序列化情况下的create、update就不再调用ModelSerializer的
    	# 而是调用 ModelSerializer.Meta.list_serializer_class 指向的 ListSerializer 类的create、update
    	# ListSerializer默认只实现了群增的create,要实现群改,必须重写update
    	
    	class MyListSerializer(ListSerializer):
        	def update(self, instance, validated_data):
                # print(instance)  # 要更新的对象们: [obj1, obj2, ...]
                # print(validated_data)  # 更新的对象对应的数据们: [{}, {}, ...]
                # print(self.child)  # 服务的模型序列化类 - V2BookModelSerializer
                for index, obj in enumerate(instance):
                    self.child.update(obj, validated_data[index])
                return instance
                
         class MyModelSerializer(ModelSerializer):
         	class Meta:
         		# ...
         		list_serializer_class = MyListSerializer
         
         将两者类建立关联,在MyListSerializer中就可以用self.child拿到MyModelSerializer,进而使用MyModelSerializer中封装好的方法
         cls.Meta.list_serializer_class.child = cls
    """
    

    视图类传递参数给序列化类

    view=> serlizer

    """
     自己的话:
     就是说view视图要传参给序列化类,只能通过context传,
    """
    
    
    
    # 1)在视图类中实例化序列化对象时,可以设置context内容
    # 2)在序列化类中的局部钩子、全局钩子、create、update方法中,都可以用self.context访问视图类传递过来的内容
    
    
    # 需求:
    # 1) 在视图类中,可以通过request得到登陆用户request.user
    # 2) 在序列化类中,要完成数据库数据的校验与入库操作,可能会需要知道当前的登陆用户,但序列化类无法访问request
    # 3) 在视图类中实例化序列化对象时,将request对象传递进去
    
    视图层:views.py
    class Book(APIView):
        def post(self, request, *args, **kwargs):
            book_ser = serializers.BookModelSerializer(data=request_data,context={'request':request})# 直接将request传过去,序列化类到时候想拿什么就拿什么
            book_ser.is_valid(raise_exception=True)
            book_result = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.BookModelSerializer(book_result).data
            })
    
    序列化层:serializers.py
    # 通常情况下,这种request在全局或者局部钩子中存在,用来确定用户名是否一致 
    # 这是request的值:{’request': <rest_ _framework. request. Request object at 0x000001C7C1762AC8>}。这就是一个字典,因此可以get取值。
    # 通过request也可以获取前端访问的方式,用.method来访问即可
    
    class BookModelSerializer(ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('name', 'price')
        def validate_name(self, value):
            print(self.context.get('request').method)
            return value
    

    封装Response类

    用途:我们在view中写对应请求方法的时候会重复写Response方法,这需要简化操作

    实现(如下):使得自定义一个Myresponse()直接就替代了之前写的Response({'status': 0,'msg': 'ok'})

    # 
    """
    Response({
        'status': 0,
        'msg': 'ok',
        'results': [],
        'token': ''  # 有这样的额外的key-value数据结果
    },status=http_status,headers=headers,exception=True|False)
    
    APIResponse() => Response({'status': 0,'msg': 'ok'})
    """
    
    # 注意下面if results is not None的写法的原因!!!!
    from rest_framework.response import Response
    
    class APIResponse(Response):
        def __init__(self, data_status=0, data_msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs):
            # data的初始状态:状态码与状态信息
            data = {
                'status': data_status,
                'msg': data_msg,
            }
            # data的响应数据体
            # results可能是False、0等数据,这些数据某些情况下也会作为合法数据返回
            if results is not None:# 当results是0时,我们用if results:这样就不行了,必须用results不等于None才行!!
                data['results'] = results# 并且results有值得时候必须添加到data中
            # data响应的其他内容
            # 以下两个是对传额外数据如:'token': ''  # 有这样的额外的key-value数据结果,添加到data中的方法
            # 字典增值得方式1
            # if kwargs is not None:
            #     for k, v in kwargs.items():
            #         setattr(data, k, v)
            # 字典增值得方式2
            data.update(kwargs)
    
            super().__init__(data=data, status=http_status, headers=headers, exception=exception)# 这个super就是调用的下面这个方法
    

    1571549231720

    小知识点

    1571553859789

    view传的参数:
    
    book_objs_data = serializers.V2BookModelSerializer(book_objs, many=True).data
    
    return APIResponse(1, 'ooo', token="123.abc.xyz", results=book_objs_data, http_status=201)
    

    视图家族

    """
    views:视图
    Generics:工具视图
    mixins:视图工具集
    viewsets:视图集
    """
    """
    学习曲线
    APIView(继承apiview,禁用csrf) => GenericAPIView => mixins的五大工具类 => generics中的工具视图 => viewsets中的视图集
    """
    

    GenericAPIView基类:工具视图

    # GenericAPIView是继承APIView的,使用完全兼容APIView
    # 重点:GenericAPIView在APIView基础上完成了哪些事
        # 1)get_queryset():(从类属性queryset中获得model的queryset数据)现在可以替换models.Book.objects.filter(is_delete=False)这句话
        
        # 2)get_object():从类属性queryset中获得model的queryset数据,再通过有名分组pk确定唯一操作对象
        
        # 3)get_serializer():(从类属性serializer_class中获得serializer的序列化类)现在可以替换serializers.BookModelSerializer(book_query, many=True)
    
    urlpatterns = [
        url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
        url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),
    ]
    
    from rest_framework.generics import GenericAPIView
    class BookGenericAPIView(GenericAPIView):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BookModelSerializer
        # 自定义主键的 有名分组 名
        lookup_field = 'pk'
        # 群取(上面三句加群取)
        # def get(self, request, *args, **kwargs):
        #     book_query = self.get_queryset()
        #     book_ser = self.get_serializer(book_query, many=True)
        #     book_data = book_ser.data
        #     return APIResponse(results=book_data)
    
        # 单取
        def get(self, request, *args, **kwargs):
            book_query = self.get_object()
            book_ser = self.get_serializer(book_query)
            book_data = book_ser.data
            return APIResponse(results=book_data)
    

    1571554582109

    GenericAPIView是继承APIView的,使用完全兼容APIView
    # 这样使得bookAPIView和GenericAPIView代码可以是一模一样并能获得同样的结果!!
    class BookAPIView(APIView):
        def get(self, request, *args, **kwargs):
            book_query = models.Book.objects.filter(is_delete=False).all()
            book_ser = serializers.BookModelSerializer(book_query, many=True)
            book_data = book_ser.data
            return APIResponse(results=book_data)
    
    GenericAPIView在APIView基础上完成这3件事

    1571554859017

    mixins视图工具集 - 辅助GenericAPIView

    用途:简化函数体的代码量!

    # 1)mixins有五个工具类文件,一共提供了五个工具类,六个工具方法:单查、群查、单增、单删(不用)、单整体改、单局部改
    # 2)继承工具类可以简化请求函数的实现体,但是必须继承GenericAPIView,需要GenericAPIView类提供的几个类属性和方法(见上方GenericAPIView基类知识点)
    # 3)工具类的工具方法返回值都是Response类型对象,如果要格式化数据格式再返回给前台,可以通过 response.data 拿到工具方法返回的Response类型对象的响应数据
    
    urlpatterns = [
       	url(r'^v3/books/$', views.BookMixinGenericAPIView.as_view()),
        url(r'^v3/books/(?P<pk>.*)/$', views.BookMixinGenericAPIView.as_view()),
    ]
    
    from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin
    class BookMixinGenericAPIView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BookModelSerializer
    
        def get(self, request, *args, **kwargs):# 这里面是单和群查在一起的
            if 'pk' in kwargs:
                response = self.retrieve(request, *args, **kwargs)#retrieve单查
            else:
                # mixins提供的list方法的响应对象是Response(就是说它用的默认response返回,缺少一个状态码),想将该对象格式化为APIResponse,就是我们自定义的response,为其返回给前台的数据加上status。
                response = self.list(request, *args, **kwargs)# list群查
            # response的数据都存放在response.data中
            return APIResponse(results=response.data)
    
        def post(self, request, *args, **kwargs):# 单增
            response = self.create(request, *args, **kwargs)# 注意增的时候不需要self
            return APIResponse(results=response.data)
    
        def put(self, request, *args, **kwargs):# 单整体改
            response = self.update(request, *args, **kwargs)
            return APIResponse(results=response.data)
    
        def patch(self, request, *args, **kwargs):# 单局部改
            response = self.partial_update(request, *args, **kwargs)
            return APIResponse(results=response.data)
    

    1571556446891

    list和apiresponse的结合图示:

    list能返回除了status之外的信息

    1571556785117

    工具视图

    更简便我们的代码量

    我们原本群查和单曾仅仅要写的两句话也被省略了! !

    # 1)工具视图都是GenericAPIView的子类,且不同的子类继承了不听的工具类,重写了请求方法
    # 2)工具视图的功能如果直接可以满足需求,只需要继承工具视图,提供queryset与serializer_class即可
    
    urlpatterns = [
       	url(r'^v4/books/$', views.BookListCreatePIView.as_view()),
        url(r'^v4/books/(?P<pk>.*)/$', views.BookListCreatePIView.as_view()),
    ]
    
    # 
    from rest_framework.generics import ListCreateAPIView, UpdateAPIView
    class BookListCreatePIView(ListCreateAPIView, UpdateAPIView):# 写了updateAPIView就是群改和单改的功能
        # 因为这是APIView的子类,因此要写下面两句话
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BookModelSerializer
    

    1571558455716

    视图集

    # 1)视图集都是优先继承ViewSetMixin类,再继承一个视图类(GenericAPIView或APIView)
    #       GenericViewSet、ViewSet
    # 2)ViewSetMixin提供了重写的as_view()方法,继承视图集的视图类,配置路由时调用as_view()必须传入 请求名-函数名 映射关系字典
    #       eg: url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
    #       表示get请求会交给my_get_list视图函数处理
    
    urlpatterns = [
       	# View的as_view():将get请求映射到视图类的get方法
        # ViewSet的as_view({'get': 'my_get_list'}):将get请求映射到视图类的my_get_list方法
        url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
        url(r'^v5/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({'get': 'my_get_obj'})),
    ]
    
    from rest_framework.viewsets import GenericViewSet
    from rest_framework import mixins
    class BookGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BookModelSerializer
    
        def my_get_list(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def my_get_obj(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)# retrieve单查
    

    GenericAPIView 与 APIView 最为两大继承视图的区别

    # 1)GenericViewSet和ViewSet都继承了ViewSetMixin,as_view都可以配置 请求-函数 映射
    # 2)GenericViewSet继承的是GenericAPIView视图类,用来完成标准的 model 类操作接口
    # 3)ViewSet继承的是APIView视图类,用来完成不需要 model 类参与,或是非标准的 model 类操作接口
    #       post请求在标准的 model 类操作下就是新增接口,登陆的post不满足
    #       post请求验证码的接口,不需要 model 类的参与
        # 案例:登陆的post请求,并不是完成数据的新增,只是用post提交数据,得到的结果也不是登陆的用户信息,而是登陆的认证信息
    

    工具视图集

    urlpatterns = [
       	url(r'^v6/books/$', views.BookModelViewSet.as_view({'get': 'list', 'post': 'create'})),
        url(r'^v6/books/(?P<pk>.*)/$', views.BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
    ]
    
    from rest_framework.viewsets import ModelViewSet
    class BookModelViewSet(ModelViewSet):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BookModelSerializer
    
        # 删不是数据库,而是该记录中的删除字段
        def destroy(self, request, *args, **kwargs):
            instance = self.get_object()  # type: models.Book
            if not instance:
                return APIResponse(1, '删除失败')  # 实际操作,在此之前就做了判断
            instance.is_delete = True
            instance.save()
            return APIResponse(0, '删除成功')
    

    路由组件(了解)

    from django.conf.urls import include
    from rest_framework.routers import SimpleRouter
    router = SimpleRouter()
    # 所有路由与ViewSet视图类的都可以注册,会产生 '^v6/books/$' 和 '^v6/books/(?P<pk>[^/.]+)/$'
    router.register('v6/books', views.BookModelViewSet)
    
    urlpatterns = [
        # 第一种添加子列表方式
        url(r'^', include(router.urls)),
    ]
    # 第二种添加子列表方式
    # urlpatterns.extend(router.urls)
    
  • 相关阅读:
    稳扎稳打Silverlight(13) 2.0交互之鼠标事件和键盘事件
    稳扎稳打Silverlight(17) 2.0数据之详解DataGrid, 绑定数据到ListBox
    再接再厉VS 2008 sp1 + .NET 3.5 sp1(2) Entity Framework(实体框架)之详解 Linq To Entities 之一
    稳扎稳打Silverlight(8) 2.0图形之基类System.Windows.Shapes.Shape
    稳扎稳打Silverlight(11) 2.0动画之ColorAnimation, DoubleAnimation, PointAnimation, 内插关键帧动画
    稳扎稳打Silverlight(21) 2.0通信之WebRequest和WebResponse, 对指定的URI发出请求以及接收响应
    稳扎稳打Silverlight(16) 2.0数据之独立存储(Isolated Storage)
    稳扎稳打Silverlight(9) 2.0画笔之SolidColorBrush, ImageBrush, VideoBrush, LinearGradientBrush, RadialGradientBrush
    稳扎稳打Silverlight(23) 2.0通信之调用WCF的双向通信(Duplex Service)
    游戏人生Silverlight(1) 七彩俄罗斯方块[Silverlight 2.0(c#)]
  • 原文地址:https://www.cnblogs.com/ZDQ1/p/11720971.html
Copyright © 2011-2022 走看看