ModelSerializer 高级使用 (2)

   上面没有涉及到查询多条,那么在查询多条时我们会传递进many参数,在内部会执行这样一段代码:

def __new__(cls, *args, **kwargs): # We override this method in order to automatically create # `ListSerializer` classes instead when `many=True` is set. if kwargs.pop('many', False): return cls.many_init(*args, **kwargs) return super().__new__(cls, *args, **kwargs)

   这句代码的意思是,当有many为True时代表这是多条操作,它将不会实例化你的自定义序列化器,因为你的自定义序列化器都是针对单条记录的,转而它会实例化一个叫做ListSerializer的类,该类是内置的,并且该类支持批量创建。

   下面是ListSerializer的部分源码,其中child代表你自定义的序列化器:

class ListSerializer(BaseSerializer): child = None # 代表你自己写的序列化器 many = True default_error_messages = { 'not_a_list': _('Expected a list of items but got type "{input_type}".'), 'empty': _('This list may not be empty.') } def __init__(self, *args, **kwargs): self.child = kwargs.pop('child', copy.deepcopy(self.child)) # 自己写的序列化器 self.allow_empty = kwargs.pop('allow_empty', True) assert self.child is not None, '`child` is a required argument.' assert not inspect.isclass(self.child), '`child` has not been instantiated.' super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self)

   继续向下看它的源码,可以发现它是支持批量创建的,但是不支持批量更新。

def update(self, instance, validated_data): raise NotImplementedError( "Serializers with many=True do not support multiple update by " "default, only multiple create. For updates it is unclear how to " "deal with insertions and deletions. If you need to support " "multiple update, use a `ListSerializer` class and override " "`.update()` so you can specify the behavior exactly." ) def create(self, validated_data): return [ self.child.create(attrs) for attrs in validated_data ]

   如果我们对自己的序列化器做一个ListSerializer,则可以继承原生的ListSerializer,并且指定好当有many参数传递时,实例化的是我们自己写的ListSerializer即可。如下所示:

from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ListSerializer from app01 import models # 写一个类,继承ListSerializer,重写update方法实现批量更新 class BookListSerializer(ListSerializer): def update(self,instance,validated_data): return [ self.child.update(instance[i],attrs) for i,attrs in enumerate(validated_data) ] class BookModelSerializer(ModelSerializer): class Meta: list_serializer_class = BookListSerializer # 使用many参数后后用指定的类进行实例化 model = models.Book # depth=0 # 序列化的关联层级 fields = ("pk","book_name","book_price","authors","publish","publish_name","author_list") # 使用property来拿到展示的数据 extra_kwargs = { "publish":{"write_only":True}, # 不展示,但是新增或更新需要指定 "publish_name":{"read_only":True}, # 仅用于展示 "authors":{"write_only":True}, "author_list":{"read_only":True}, }

   总结如下:

   1.我们自己写的序列化器都只能对单条进行操作

   2.如果传入many为True时,则会自动序列化一个内部的ListSerializer类,它支持批量创建多条,但是不支持批量更新

   3.在自定义序列器中使用list_serializer_class类属性即可指定在进行批量操纵时用哪一个类进行实例化

序列化与反序列化

   查看上面的代码,你可以发现在model中的很多地方都用了property来对实例方法进行装饰。

   它其实是为了配合序列化做的,因为我们在自定以序列化器中的fields属性里将他们进行加入了,如下所示:

@property def publish_name(self): # 模拟字段,用于序列化时显示出版社名称 return self.publish.publish_name @property def author_list(self): # 模拟字段,用于序列化时显示多个作者的名字和性别 author_list = self.authors.all() return [ {"author_name":author.author_name,"author_gender":author.get_author_gender_display()} for author in author_list ] fields = ("pk","book_name","book_price","authors","publish","publish_name","author_list") # 返回外键,出版社的名字,返回多对多外键,作者的列表

   并且,还指定了extra_kwargs参数,用于指定哪些参数是序列化时用,哪些参数是反序列化时用:

extra_kwargs = { "publish":{"write_only":True}, # 不展示,但是新增或更新需要指定 "publish_name":{"read_only":True}, # 仅用于展示 "authors":{"write_only":True}, "author_list":{"read_only":True}, }

   这其实也要与前端沟通好,我序列化丢给你的数据是字符串,但是你要创建时必须给我把诸如出版社、作者等信息的pk放进来才行。

   大概意思就是,我丢给你字符串让用户看,你创建或更新时我不要字符串,我要pk主键。

   此外,还有一个参数叫做depth,它规定了在序列化时是否连同外键一起进行序列化,并且序列化的层级是多少,一般看一看就行了。

接口书写

   规定,对于单条操作,直接放在?请求地址后面。放入pk即可。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxdzx.html