zoukankan      html  css  js  c++  java
  • 二次封装 Reponse,视图家族

    复习

    """
    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
    """
    

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

    # 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})
            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
    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类

    """
    Response({
        'status': 0,
        'msg': 'ok',
        'results': [],
        'token': ''  # 有这样的额外的key-value数据结果
    },status=http_status,headers=headers,exception=True|False)
    
    APIResponse() => Response({'status': 0,'msg': 'ok'})
    """
    
    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:
                data['results'] = results
            # data响应的其他内容
            # if kwargs is not None:
            #     for k, v in kwargs.items():
            #         setattr(data, k, v)
            data.update(kwargs)
    
            super().__init__(data=data, status=http_status, headers=headers, exception=exception)
    

    视图家族

    """
    views:视图
    generics:工具视图
    mixins:视图工具集
    viewsets:视图集
    """
    """
    学习曲线
    APIView => GenericAPIView => mixins的五大工具类 => generics中的工具视图 => viewsets中的视图集
    """
    

    GenericAPIView基类

    # GenericAPIView是继承APIView的,使用完全兼容APIView
    # 重点:GenericAPIView在APIView基础上完成了哪些事
    # 1)get_queryset():从类属性queryset中获得model的queryset数据
    # 2)get_object():从类属性queryset中获得model的queryset数据,再通过有名分组pk确定唯一操作对象
    # 3)get_serializer():从类属性serializer_class中获得serializer的序列化类
    
    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)
    

    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)
            else:
                # mixins提供的list方法的响应对象是Response,想将该对象格式化为APIResponse
                response = self.list(request, *args, **kwargs)
            # response的数据都存放在response.data中
            return APIResponse(results=response.data)
    
        def post(self, request, *args, **kwargs):
            response = self.create(request, *args, **kwargs)
            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)
    

    工具视图

    # 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):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BookModelSerializer
    

    视图集

    # 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)
    

    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)
    
  • 相关阅读:
    Java实现 LeetCode 735 行星碰撞(栈)
    Java实现 LeetCode 735 行星碰撞(栈)
    Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
    Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
    Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
    Java实现 蓝桥杯算法提高 求最大值
    Java实现 蓝桥杯算法提高 求最大值
    Java实现 蓝桥杯算法提高 求最大值
    Python eval() 函数
    Python repr() 函数
  • 原文地址:https://www.cnblogs.com/DcentMan/p/11706067.html
Copyright © 2011-2022 走看看