Title(EN): Django REST Framework Learning Notes (9): the ListSerializer class in serialziers module
Author: dog2
基本信息
源码:rest_framework.serializers
官方文档
API Guide - Serializers
API Guide - Serializer fields
API Guide - Serializer relations
本文demo代码Github
DRF常用序列化类主要有
rest_framework.serialziers.Serializer
rest_framework.serialziers.ModelSerializer
rest_framework.serialziers.ListSerializer
本篇介绍rest_framework.serialziers.ListSerializer
,将继续以图书管理系统实例说明。
使用场景之群改群增群改
当一个序列化器在带有many=True
选项被序列化时,将创建一个ListSerializer
实例,该序列化器类将成为ListSerializer
类的子类。 当你需要自定义多个对象的行为时(比如群增,群改),你需要手动定制ListSerializer
类的一些行为。 可以通过在自定义序列化器的Meta
类下面的list_serializer_class
来绑定你需要的的ListSerializer
类
示例代码
群改需要设置ListSerializer
,创建BookListSerializer
继承ListSerializer
,重写update
方法
序列化层 serializer.py
1 2 3 4 5 6 7 8 9 10 11 12 13 class BookListSerializer (ListSerializer) : def update (self, instance, validated_data) : for index, obj in enumerate(instance): self.child.update(obj, validated_data[index]) return instance class V3BookModelSerializer (ModelSerializer) : class Meta : list_serializer_class = BookListSerializer
之所以需要实现update
方法,群改时会走 rest_framework.serializers.ListSerializer
中的update
函数,而该函数并未被实现。
而群增不需要重写create
方法,因为源码中rest_framework.serializers.ListSerializer
走的就是ModelSerializer
的create
方法:
1 2 3 4 def create (self, validated_data) : return [ self.child.create(attrs) for attrs in validated_data ]
视图层 views.py
在视图层将 单局部改和群局部改整合,思路如下:
单局部改:对 v3/books/pk/
pk
通过路由传参,修改数据选择传参,通过数据包json传递
群局部修改:v3/books/
修改数据通过数据包传递,设置成列表格式 [{pk:1,name:123},{pk:3,price:7},{pk:7,publish:2}]
先将单改,群改的数据都格式化成 pks=[要需要的对象主键标识]
, request_data=[每个要修改的对象对应的修改数据]
pks
与request_data
数据筛选,将pks
中的没有对应数据的pk
与数据已删除的pk
移除,request_data
对应索引位上的数据也移除,将合理的pks
转换为objs
Source Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom . import models, serializersclass V3Book (APIView) : def patch (self, request, *args, **kwargs) : request_data = request.data pk = kwargs.get('pk' ) if pk and isinstance(request_data, dict): pks = [pk, ] request_data = [request_data, ] elif not pk and isinstance(request_data, list): pks = [] for dic in request_data: pk = dic.pop('pk' , None ) if pk: pks.append(pk) else : return Response({ 'status' : 1 , 'msg' : '参数错误' }) else : return Response({ 'status' : 1 , 'msg' : '参数错误' }) objs = [] new_request_data = [] for index, pk in enumerate(pks): try : book_obj = models.Book.objects.get(pk=pk, is_delete=False ) objs.append(book_obj) new_request_data.append(request_data[index]) except : continue book_ser = serializers.V3BookModelSerializer( 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.V3BookModelSerializer(book_objs, many=True ).data })
ListSerializer
使用要点小结
views.py
1 ser_obj = ModelSerializer(instance=model_obj,data=model_data,partial=True ,many=True )
serializer.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class MyListSerializer (ListSerializer) : def update (self, instance, validated_data) : for index, obj in enumerate(instance): self.child.update(obj, validated_data[index]) return instance class MyModelSerializer (ModelSerializer) : class Meta : list_serializer_class = MyListSerializer cls.Meta.list_serializer_class.child = cls
源码补充分析
分析一下修改为什么要用instance
传参。
修改之后数据使用save()
保存,从视图的save()
点击进去查看源码,下面是BaseSerializer
类中的save
,而该save
未被实现。
因此接着查看save
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def save (self, **kwargs) : validated_data = [ dict(list(attrs.items()) + list(kwargs.items())) for attrs in self.validated_data ] if self.instance is not None : self.instance = self.update(self.instance, validated_data) assert self.instance is not None , ( '`update()` did not return an object instance.' ) else : self.instance = self.create(validated_data) assert self.instance is not None , ( '`create()` did not return an object instance.' ) return self.instance
instance
存在就走update
方法,修改数据(PUT
/PATCH
)时都应传入instance
,所以单改群改都需要传入data
(反序列化用)和instance
(序列化用)参数。