rest_framework序列化类的继承关系
field类:
序列化基类的基类 BaseSerializer:
继承field
派生ListSerializer序列化类 Serializer:
继承SerializerMetaClass
继承BaseSerializer ModelSerializer:
继承Serializer HyperlinkedModelSerializer:
继承ModelSerializer
反序列化流程
  1. 生成序列化对象serializer([instance],data=request.data)
  2. 数据验证:is_valid()
  3. 生成:validated_data
  4. 调用save方法
  5. 根据是否有instance,分别调用create或者update
  6. 返回serializer.data
除了ListSerializer类不太一样
BaseSerializer和Serializer、ModelSerializer三个类的is_valid和save则是完全一样
create和update只有ModelSerializer有直接实现
HyperLinkedModelSerializer是继承ModelSerializer基础上增加了url字段和嵌套
create()源码
# BaseSerializer中的create
def create(self, validated_data):
raise NotImplementedError('`create()` must be implemented.')
#在Baseserliazer序列化基类的时候,创建了create方法
# 但是并没有具体去实现他,只是抛出未实现的异常
 '''
Serializer继承BaseSerializer,没有直接提供写好的create方法
所以我们继承Serializer实现序列化的时候,需要自己去写create
ModelSerializer源码中实现了create,可以直接使用
'''
# ModelSerializer源码中的create
def create(self, validated_data): raise_errors_on_nested_writes('create', self, validated_data) ModelClass = self.Meta.model # 获取模型类 info = model_meta.get_field_info(ModelClass) # 获取字段信息赋值给info
many_to_many = {} #多对多空字典
for field_name, relation_info in info.relations.items(): # 遍历info中的字段信息
# 如果是多对多字段全部拿出去后面单独处理
if relation_info.to_many and (field_name in validated_data):
many_to_many[field_name] = validated_data.pop(field_name) try:
# 生成模型的实例对象,赋值给instance
instance = ModelClass._default_manager.create(**validated_data)
except TypeError: # 异常捕获类型错误
tb = traceback.format_exc()
msg = (
'Got a `TypeError` when calling `%s.%s.create()`. '
'This may be because you have a writable field on the '
'serializer class that is not a valid argument to '
'`%s.%s.create()`. You may need to make the field '
'read-only, or override the %s.create() method to handle '
'this correctly.\nOriginal exception was:\n %s' %
(
ModelClass.__name__,
ModelClass._default_manager.name,
ModelClass.__name__,
ModelClass._default_manager.name,
self.__class__.__name__,
tb
)
)
raise TypeError(msg) # Save many-to-many relationships after the instance is created.
if many_to_many: # 如果多对多有值字典有值
for field_name, value in many_to_many.items(): # 遍历多对多信息字典
field = getattr(instance, field_name) #通过getattr生成对应实例
field.set(value) #将value保存 return instance
'''
整体逻辑就是先将每个字段的值拿出来,先用非多对多字段的值创建模型实例
最后遍历多对多字段值保持到实例,最后返回
'''
update()源码
'''
update同样也是在BaseSerializer中留下了对应方法的位置待后续实现
Serializer中没有做具体实现,直接继承Serializer类需要自己实现update
下面是ModelSerializer中实现的update源码
''' def update(self, instance, validated_data):
raise_errors_on_nested_writes('update', self, validated_data)
info = model_meta.get_field_info(instance)
m2m_fields = []
for attr, value in validated_data.items(): #直接遍历所有已验证的数据,不区分多对多关系 # 如果是多对多字段,
if attr in info.relations and info.relations[attr].to_many:
m2m_fields.append((attr, value)) #追加到m2m
else:
setattr(instance, attr, value) # 更新字段数据 instance.save() for attr, value in m2m_fields: #遍历m2m字段
field = getattr(instance, attr) # 更新数据
field.set(value) return instance
is_valid源码
'''
is_valid在BaseSerializer中有直接实现
'''
def is_valid(self, raise_exception=False):
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
) if not hasattr(self, '_validated_data'): # 如果没有self._validated_data
try: #使用self.run_validation验证数据,如果没有问题赋值给self._validated_data
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {} #如果有问题将_validated_data赋值为一个空字典
self._errors = exc.detail # errors信息
else:
self._errors = {} if self._errors and raise_exception: # 如果有erroes信息和raise_exception设置为True
raise ValidationError(self.errors) #抛出ValidationError异常信息 return not bool(self._errors) #如果self._errors没有值就是一个空字典,bool就是False,not bool就是True
 
save()
def save(self, **kwargs):
# 断言否包含error
assert hasattr(self, '_errors'), (
'You must call `.is_valid()` before calling `.save()`.'
) # 断言 self.errors是否有错误信息
assert not self.errors, (
'You cannot call `.save()` on a serializer with invalid data.'
) # 检查参数是否包含commit字段
assert 'commit' not in kwargs, (
"'commit' is not a valid keyword argument to the 'save()' method. "
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
"You can also pass additional keyword arguments to 'save()' if you "
"need to set extra attributes on the saved model instance. "
"For example: 'serializer.save(owner=request.user)'.'"
)
# 检查是否是使用self._data后调用.save()
assert not hasattr(self, '_data'), (
"You cannot call `.save()` after accessing `serializer.data`."
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
)
# 经过合格验证的数据,self.validated_data的每一项和kwargs的每一项
validated_data = {**self.validated_data, **kwargs} # 通过判断instance是否有值来决定是更新操作还是创建操作
if self.instance is not None: #如果有值
# 调用update并且返回对应结果
self.instance = self.update(self.instance, validated_data)
# 断言更新后的结果来判断是否更新成功
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:#如果没有instance,就执行create方法
self.instance = self.create(validated_data)
#断言创建结果
assert self.instance is not None, (
'`create()` did not return an object instance.'
) return self.instance
 
传递附加属性到save方法
'''
一般来说我们调用save是不传值
下方代码调用save的时候,传递了owner=self.request.user
owner模型类的一个字段
'''
def perfortm_create(self,serializer):
serializer.save(owner=self.request.user) '''
save源码中的validated_data = {**self.validated_data, **kwargs}
除了self.validated_data以外,还有kwargs
所以validated_data是 self.validated_data验证过的数据 和 附加数据 kwargs组合起来的一个dict
'''
 
重写save方法
'''
一般来说 save方法是去找create或者update方法来做数据更新、创建
''' class EmailSerializer(serializer.Serializer):
email = serializers.EmailField()
message = serializer.CharField() def save(self):
email = self.validated_data['email'] #拿到经过验证的email字段
message = self.validated_data['message'] #拿到经过验证的message的字段
send_meail(from=email,message=message) #发送邮件 '''
上面的代码直接重写了save方法,覆盖源码的save,不再具有更新、创建的功能
is_valid\save\create\update是反序列化的最重要的几个逻辑方法
在序列化中,我们可以完完全全重写几个方法源码的逻辑根据我们的业务逻辑来定制我们的场景
'''
 

30.Serializers模块源码解析的更多相关文章

  1. gorm的日志模块源码解析

    gorm的日志模块源码解析 如何让gorm的日志按照我的格式进行输出 这个问题是<如何为gorm日志加traceId>之后,一个群里的朋友问我的.如何让gorm的sql日志不打印到控制台, ...

  2. 「从零单排canal 06」 instance模块源码解析

    基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...

  3. php 日志模块源码解析

    php日志模块设计 Monolog 是PHP的一个日志类库解析 整体介绍:monolog日志模块遵循 PSR3 的接口规范.主要有日志格式类接口(格式化日志信息),处理类接口(写日志的驱动,通过扩展写 ...

  4. C#软件授权、注册、加密、解密模块源码解析并制作注册机生成license

    最近做了一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制.事出突然,只能在现场开发(离开现场软件就不受我们控了).花了不到两个小时实现了简单的注册机制,稍作整理.        ...

  5. 「从零单排canal 05」 server模块源码解析

    基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...

  6. 「从零单排canal 07」 parser模块源码解析

    基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...

  7. python Threading模块源码解析

    查看源码: 这是一个线程控制的类,这个类可以被子类化(继承)在一定的条件限制下,这里有两种方式去明确活动:第一通过传入一个callable 对象也就是调用对象,一种是通过重写这个Thread类的run ...

  8. 【nodejs原理&源码赏析(4)】深度剖析cluster模块源码与node.js多进程(上)

    [摘要] 集群管理模块cluster浅析 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 概述 cluster模块是node.js中用于实现和管理 ...

  9. 【nodejs原理&源码赏析(4)】深度剖析cluster模块源码与node.js多进程(上)

    目录 一. 概述 二. 线程与进程 三. cluster模块源码解析 3.1 起步 3.2 入口 3.3 主进程模块master.js 3.4 子进程模块child.js 四. 小结 示例代码托管在: ...

随机推荐

  1. 重构、插件化、性能提升 20 倍,Apache DolphinScheduler 2.0 alpha 发布亮点太多!

    点击上方 蓝字关注我们 社区的小伙伴们,好消息!经过 100 多位社区贡献者近 10 个月的共同努力,我们很高兴地宣布 Apache DolphinScheduler 2.0 alpha 发布.这是 ...

  2. HDU 1542/POJ 1151 Atlantis (scaning line + segment tree)

    A template of discretization + scaning line + segment tree. It's easy to understand, but a little di ...

  3. selenium基本用法

    一.元素操作 send_keys:赋值 clear:清空 click:点击 from selenium import webdriver from selenium.webdriver.common. ...

  4. postgresql用户与权限管理

    pg使用角色的概念管理数据库访问权限,角色是一系列相关权限的集合.为了管理方便,通常把一系列先关的权限赋予给一个角色,如果哪个用户需要这些权限,就把这些角色赋予给响应的用户. 由于用户也拥有一系列的相 ...

  5. 「2020-2021 集训队作业」Yet Another Linear Algebra Problem(行列式,Binet-Cauchy 公式)

    题面 出题人:T L Y \tt TLY TLY 太阳神:Tiw_Air_OAO 「 2020 - 2021 集 训 队 作 业 」 Y e t A n o t h e r L i n e a r A ...

  6. TMC2209步进驱动芯片基本配置及使用

    TMC2209是用于两相步进电机的超静音电机驱动器IC. TMC2209与许多传统驱动器以及TMC2208引脚兼容. TRINAMICs先进的StealthChop2斩波器可确保电机无噪音运行,实现最 ...

  7. Java中数组

    数组的定义格式: 1: 数据类型[] 数组名 2: 数据类型 数组名 动态初始化: 初始化的时候 系统会默认给数组赋值 数据类型[] 变量名 = new 数据类型[数组长度] int[] arr = ...

  8. 第六十篇:Vue的基本使用

    好家伙,要来了,经典"hello world" 试用一下vue ① 导入 vue.js的 script 脚本文件 ② 在页面中声明一个将要被vue所控制的DOM区域 ③ 创建vm实 ...

  9. 干货分享!JAVA诊断工具Arthas在Rainbond上实践~

    别再担心线上 Java 业务出问题怎么办了,Arthas 帮助你解决以下常见问题: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 我改的代码为什么没有执行到?难道是我没 ...

  10. 【pytest官方文档】解读- 如何安装和使用插件

    本节讨论安装和使用第三方插件.关于编写自己的插件,我们下一章继续. 一.pip 安装 就像安装一些其他第三方库一样,使用pip也可以很容易地安装第三方插件,pytest-NAME这是你要安装的插件名称 ...