Loading

序列化类源码分析

序列化类源码分析

​ 我们主要带着两个问题取探究

  1. 反序列化类校验是如何走的局部钩子和全局钩子
  2. 序列化类实例化分单条和多条,它们实例化得到的对象是不一样的(不同的类)

单条和多条的序列化类的实例化

​ 首先当我们去查多条和查一条时,会在我们定义的序列化类传入参数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
posted @ 2024-04-22 16:35  HuangQiaoqi  阅读(3)  评论(0编辑  收藏  举报