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方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM