zoukankan      html  css  js  c++  java
  • DRF框架(四)——单整体改(put)、单局部改(patch)、群局部改(patch)--ListSerializer

    单整体改   单指的是单独一条数据,整体指这条数据的设置不为空字段都必须传值修改

    基于上篇文章的代码修改,序列化层不用变,只修改views.py

    1)单整体改,说明前台要提供修改的数据,修改之后保存的数据需要校验,校验的数据应该在实例化“序列化类对象”时,赋值给data
    2)修改,就必须明确被修改的模型类对象,并在实例化“序列化类对象”时,赋值给instance,必须赋值给instance
    3)整体修改,所有校验规则有required=True的字段,都必须提供,因为在实例化“序列化类对象”时,参数partial默认为False
    
    注:如果partial值设置为True,就是可以局部改
    1)单整体修改,一般用put请求:
    V2BookModelSerializer(
        instance=要被更新的对象, 
        data=用来更新的数据,
        partial=默认False,必须的字段全部参与校验
    )
    2)单局部修改,一般用patch请求:
    V2BookModelSerializer(
        instance=要被更新的对象, 
        data=用来更新的数据,
        partial=设置True,必须的字段都变为选填字段
    )
        注:partial设置True的本质就是使字段 required=True 校验规则失效
    请求方法:put   整体修改
    请求参数:pk从路由传参,修改的数据通过数据包json传递
    请求接口: http://127.0.0.1:8080/app01/v3/books/pk/

    视图层:views.py

    #单整体改  对 v3/books/pk/  传的参数是与model对应的字典 {name|price|publish|authors}在json中传递
    class V3Book(APIView):
        def put(self,request,*args,**kwargs):
            request_data = request.data
            pk = kwargs.get('pk')
            #先获取要修改的对象
            try:
                old_book_obj = models.Book.objects.get(pk=pk,is_delete=False)
            except:
                #当输入不存在的pk
                return Response({
                    'status':1,
                    'msg':'参数错误'
                })
            book_ser = serializers.V2BookModelSerializer(instance=old_book_obj,data=request_data,partial=False)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
    
            return Response({
                'status':0,
                'msg':'ok',
                'results':serializers.V2BookModelSerializer(book_obj).data
            })

    单整体修改注意点(******)

    1.需要修改的数据通过data传递
    2.需要修改的模型类对象必须传递给instance
    3.参数partial设置为False (默认是False,这里不设置也行)

    单局部修改

    单整体修改和单局部修改只有一点不相同:

    设置参数partial=True,就变成单局部修改,修改的参数就不必全部传,想修改什么数据就传什么数据

    单局部修改和群局部修改整合      ListSerializer辅助(群增,群改)

    当一个序列化器在带有many=True选项被序列化时,将创建一个ListSerializer实例,该序列化器类将成为ListSerializer类的子类。
    当你需要自定义多个对象的行为时(比如群增,群改),你需要手动定制ListSerializer类的一些行为。
    可以通过在自定义序列化器的Meta类下面的list_serializer_class来绑定你需要的的ListSerializer类

    序列化层 serializer.py

    群改需要设置ListSerializer,创建V2BookListSerializer继承ListSerializer,重写update方法

    # 重点:ListSerializer与ModelSerializer建立关联的是: 在ModelSerializer的Meta类中设置   list_serializer_class
    class V2BookListSerializer(ListSerializer):   
      def update(self, instance, validated_data): # print(instance) # 要更新的对象们 # print(validated_data) # 更新的对象对应的数据们 # print(self.child) # 服务的模型序列化类 - V2BookModelSerializer for index, obj in enumerate(instance): self.child.update(obj, validated_data[index]) return instance # 原模型序列化类变化 class V2BookModelSerializer(ModelSerializer): class Meta: # 群改,list_serializer_class是固定的key写法,直接转入V2BookListSerializer类的 update 方法 list_serializer_class = V2BookListSerializer

    update方法源码分析: update方法里面没写东西

    群增不需要重写create方法,因为源码中ListSerializer走的就是ModelSerializer的create方法 

    create方法源码分析:

    群局部修改

    请求方式:patch
    请求参数:
      单局部修改: v3/books/pk/ pk通过路由传参,修改数据通过json传参
      群局部修改: v3/books/ 修改的数据都是从json传递 eg:[{'pk':1,'name':'花果山'},{'pk':2,'price':3.33}] 请求接口:http://127.0.0.1:8080/app01/v3/books/pk/

    视图层:views.py

     #单局部改和群局部改整合
        #单局部改:对 v3/books/pk/   pk通过路由传参,修改数据选择传参,通过数据包json传递
        #群局部修改:v3/books/ 修改数据通过数据包传递,设置成列表格式  [{pk:1,name:123},{pk:3,price:7},{pk:7,publish:2}]
        def patch(self,request,*args,**kwargs):
            request_data = request.data  #数据包数据
            pk = kwargs.get('pk')
            # 将单改,群改的数据都格式化成 pks=[要需要的对象主键标识] | request_data=[每个要修改的对象对应的修改数据]
            if pk and isinstance(request_data,dict):  #单改
                pks = [pk,]
                request_data = [request_data,]
            elif not pk and isinstance(request_data,list):  #群改
                pks = []
                # 遍历前台数据[{pk:1, name:123}, {pk:3, price:7}, {pk:7, publish:2}],拿一个个字典
                for dic in request_data:
                    pk=dic.pop('pk',None)  #返回pk值
                    if pk:
                        pks.append(pk)
                    #pk没有传值
                    else:
                        return Response({
                            'status':1,
                            'msg':'参数错误'
                        })
            else:
                return Response({
                    'status': 1,
                    'msg': '参数错误'
                })
            # pks与request_data数据筛选,
            # 1)将pks中的没有对应数据的pk与数据已删除的pk移除,request_data对应索引位上的数据也移除
            # 2)将合理的pks转换为 objs
            objs = []
            new_request_data = []
            for index,pk in enumerate(pks):
                try:
                    #将pk合理的对象数据保存下来
                    book_obj = models.Book.objects.get(pk=pk,is_delete=False)
                    objs.append(book_obj)
                    #对应索引的数据也保存下来
                    new_request_data.append(request_data[index])
                except:
                    # 重点:反面教程 - pk对应的数据有误,将对应索引的data中request_data中移除
                    #在for循环中不要使用删除
                    # index = pks.index(pk)
                    # request_data.pop(index)
                    continue
            #生成一个serializer对象
            book_ser = serializers.V2BookModelSerializer(instance=objs,data=new_request_data,partial=True,many=True)
            book_ser.is_valid(raise_exception=True)
            book_objs = book_ser.save()
    
    
            return Response({
                'status':0,
                'msg':'ok',
                'results':serializers.V2BookModelSerializer(book_objs,many=True).data
            })

    思路:

    1.先将单改,群改的数据都格式化成 pks=[要需要的对象主键标识] | request_data=[每个要修改的对象对应的修改数据]
    2.pks与request_data数据筛选,
          将pks中的没有对应数据的pk与数据已删除的pk移除,request_data对应索引位上的数据也移除
           将合理的pks转换为 objs

     注意点:

    1.本篇文章讲了局部修改patch,和整体修改put,都需要设置参数instance传入的是要修改的对象,data传入的是修改的数据
    2.群修改的话需要使用ListSerializer,重写update方法

    关于使用修改为什么要用instance传参 (源码分析)

    修改之后数据使用save()保存,从视图的save()点击进去查看源码,下面是BaseSerializer类中的save

    在这判断是否有instance属性

    有的话就走update()方法,所以我们在做修改(put,patch)的时候就要传入instance。    没有的话就走create(),创建一条新数据

    源码中发现:如果你使用的是Serializer,在视图使用save方法保存数据,但是通过源码发现Serializer类中没有save方法所以只能从他继承的BaseSerializer中走save方法。你使用的是ModelSerializer,因为ModelSerializer类中没有save方法,只能去他继承的Serializer类中找save方法,Serializer类中也没有save方法,所以最后不管你用的是Serializer还是ModelSerializer都要去BaseSerializer中找save方法。然后从save方法中去实现update和create方法。

    拓展:

    顺带提一嘴,在BaseSerializer中的update和create方法都是不起作用的,从下面源码可以看出,所以如果你的Serializer类是走的BaseSerializer的update和create方法,那么你就必须在你的Serializer类中重写update和create方法

    因为ModelSeerializer中有create和update方法,而且都是有用的,所以在ModelSeerializer中不需要重写create和update方法

  • 相关阅读:
    Java——读取和写入txt文件
    Java——去除字符串中的中文
    web.xml——Error:cvc-complex-type.2.4.a: Invalid content was found starting with element
    poi--读取不同类型的excel表格
    poi——读取excel数据
    java静态代码块
    Java-main方法中调用非static方法
    dom4j--解析xml文件
    python发送邮件
    JWT认证原理及使用
  • 原文地址:https://www.cnblogs.com/wangcuican/p/11695273.html
Copyright © 2011-2022 走看看