序列化类源码分析
我们主要带着两个问题取探究
- 反序列化类校验是如何走的局部钩子和全局钩子
- 序列化类实例化分单条和多条,它们实例化得到的对象是不一样的(不同的类)
单条和多条的序列化类的实例化
首先当我们去查多条和查一条时,会在我们定义的序列化类传入参数many=True/False,然后加括号调用,实例化得到参数。加括号这一步会指向某个类的__new__
方法。
所以首先看看__new__
方法,自己写的序列化类肯定没有---->继承的Serializer类也没有---->BaseSerializer有
__new__
def __new__(cls, *args, **kwargs):
# 判断传入给序列化类的值里面有没有many
if kwargs.pop('many', False):
# 有就执行这一句
return cls.many_init(*args, **kwargs)
# 没有就执行这一句
return super().__new__(cls, *args, **kwargs)
接下来首先看看有many的情况,也就是进入到many_init方法看看
many_init
# 首先要明白这是个绑定给类的方法
# 当前cls指的就是我们自己定义的序列化类
# 所以这里的*args, **kwargs,就是我们给序列化类传入的参数
@classmethod
def many_init(cls, *args, **kwargs):
# 把传入的参数取出,并赋值给变量
allow_empty = kwargs.pop('allow_empty', None)
max_length = kwargs.pop('max_length', None)
min_length = kwargs.pop('min_length', None)
# 类加括号得到对象
child_serializer = cls(*args, **kwargs)
# 定义一个字典,键为child,值为序列化类的对象
list_kwargs = {
'child': child_serializer,
}
# 把上面传入的参数以对应的名字传入字典
if allow_empty is not None:
list_kwargs['allow_empty'] = allow_empty
if max_length is not None:
list_kwargs['max_length'] = max_length
if min_length is not None:
list_kwargs['min_length'] = min_length
# 把剩下的参入也加到字典
list_kwargs.update({
key: value for key, value in kwargs.items()
# 这里做了一步过滤,只能穿规定的参数
if key in LIST_SERIALIZER_KWARGS
})
meta = getattr(cls, 'Meta', None)
# 如果没有再Meta类里面定义list_serializer_class属性,默认就是ListSerializer
list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
# 最后返回的时ListSerializer的对象
return list_serializer_class(*args, **list_kwargs)
所以当many的true时,得到的对象就不是当前自己定义的序列化类的对象,而是ListSerializer类的对象(在没有额外定义的情况下)
反序列化校验(如何走的钩子)
每当我们要做反序列化保存的时候就需要进行is_valid
操作,所以我们先找is_valid
看看,
自己写的类没有---->找父类Serializer,也没有---->BaseSerializer有
is_valid
首先看BaseSerializer的is_valid
# 当前self--->自定义序列化类的对象
def is_valid(self, *, raise_exception=False):
# 如果没有initial_data就会触发断言报错,意思就是没有给序列化类传data的话就会报错
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
)
# 如果没有_validated_data的情况,就是没有做过校验的时候
if not hasattr(self, '_validated_data'):
try:
# initial_data就是我们传进来的request.data
# run_validation方法解析往下看
# 就是对字段为空的不同情况做校验,然后返回数据
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
# 如果抛出异常,就把_validated_data设置为空字典
self._validated_data = {}
# 把错误消息赋值给_errors
self._errors = exc.detail
else:
# 如果没有抛出异常,就把错误信息设置为空字典
self._errors = {}
# 如果有_validated_data的情况,也就是做过校验的情况
# _errors有值且,设置了raise_exception为True,就会抛出异常
if self._errors and raise_exception为True,就会抛出异常:
raise ValidationError(self.errors)
# 如果经过了校验,且_errors没有值,就返回True
return not bool(self._errors)
run_validation
def run_validation(self, data=empty):
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# 这里就是调用了局部钩子,把值给value
value = self.to_internal_value(data)
try:
self.run_validators(value)
# 这里就是调用了自己定义的全局钩子
value = self.validate(value)
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
# 然后返回了value
return value
validate_empty_values
这个方法就是对不同情况下,对于空字段的处理,返回值是一个布尔值加上一个数据
所以run_validation
方法主要用于验证字段的空值情况,并根据情况返回默认值或者空值。
def validate_empty_values(self, data):
if self.read_only:
return (True, self.get_default())
if data is empty:
if getattr(self.root, 'partial', False):
raise SkipField()
if self.required:
self.fail('required')
return (True, self.get_default())
if data is None:
if not self.allow_null:
self.fail('null')
elif self.source == '*':
return (False, None)
return (True, None)
return (False, data)
to_internal_value
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if not isinstance(data, Mapping):
message = self.error_messages['invalid'].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='invalid')
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
# 这里就是对我们在序列化类里面定义的字段做for循环
for field in fields:
# 用validate_ 加上 字段名 拼接出一个字符串,然后再用序列化类对象做一个反射
# 这里也就是找我们有没有定义局部钩子
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
# 如果通过校验就把值返回出去
return ret
标签:分析,return,self,value,源码,kwargs,序列化,data
From: https://www.cnblogs.com/Hqqqq/p/18150896