首页 > 编程语言 >序列化类源码分析

序列化类源码分析

时间:2024-04-22 16:46:35浏览次数:37  
标签:分析 return self value 源码 kwargs 序列化 data

序列化类源码分析

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

  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

标签:分析,return,self,value,源码,kwargs,序列化,data
From: https://www.cnblogs.com/Hqqqq/p/18150896

相关文章

  • 深度解读《深度探索C++对象模型》之数据成员的存取效率分析(三)
    接下来我将持续更新“深度解读《深度探索C++对象模型》”系列,敬请期待,欢迎关注!也可以关注公众号:iShare爱分享,自动获得推文和全部的文章列表。前面两篇请通过这里查看:深度解读《深度探索C++对象模型》之数据成员的存取效率分析(一)深度解读《深度探索C++对象模型》之数据成员的......
  • 驻极体话筒(MIC)、三极管、led组成的声控led闪光电路分析
    电路:声控LED闪烁灯这里介绍一个通过声音控制LED闪光的简单电路,将它挂在室内音响或电视机的扬声器附近,LED会随喇叭播放的音色声而闪闪发光。电路图如下。 电路工作过程:1、电路上电后,周围环境无声音时,三极管Q1,基极电阻R1,集电极电阻R3,刚好是三极管的一个基极偏置电路,三极管Q1......
  • 新手大白话 [SWPU 2018]SimplePHP Phar反序列化
    今天再做个Phar反序列化巩固下。进入题目发现了查看文件与上传文件,与自己的IP。利用burp抓包进行查看,先尝试index.php,发现base.php,查看base.php发现flag所在文件,再查看file.php,发现function.phpclass.php点击查看代码class.php<?phpclassC1e4r{public$t......
  • ElasticSearch 7.17.20本地源码调试
    目录使用本地安装gradle下载相关依赖本地编译本地调试使用本地安装gradle下载相关依赖在gradle安装目录下的init.d目录中,创建初始化脚本init.gradle,添加如下脚本,将其中的maven仓库源全部换成国内镜像allprojects{repositories{defREPOSITORY_URL='http://m......
  • 二十一点玩家策略分析
    二十一点玩家策略分析我从很早开始就对二十一点(BlackJack)这个游戏感兴趣了,应该是从看了决胜21点这个电影开始的吧。前两天,我开始思考,是否真的存在电影中所说的某种方法,来降低庄家的优势,甚至战胜庄家呢?答案是确实存在某种方法降低庄家优势,但战胜庄家是不可能的。或许在过去......
  • 瑞数456vmp逆向分析
    声明本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!目标网站aHR0cHM6Ly93d3cubm1wYS5nb3YuY24v     分析debugger直接开f12触发debugger的时候直......
  • row cache lock 事后分析处理
    现场同事告知oracle19C下生产大量trc文件,把oracle目录撑爆查看trc文件如下kqrpre:keymismatchpo=0x132745948hash=27d744ca----------------------------------------SO:0x12a9d2098,type:rowcacheenqueues(111),map:0x17537fa88state:LIVE(0x4532),fl......
  • path.resolve、path.join、path.posix.join对比分析以及适用场景举例
    path.resolve、path.join、path.posix.join对比分析以及适用场景举例path.resolve、path.join和path.posix.join都是Node.js中用于处理和操作文件路径的方法,但它们各自有特定的功能和使用场景。以下是它们的对比分析和适用场景举例:1.path.resolve([...paths])功能:path.......
  • 认证组件及源码分析
    认证组件​ 用于判断用户是否登录简单使用#1.创建一个任意名字的py文件#2.导入认证类fromrest_framework.authenticationimportBaseAuthentication#3.写一个类继承它并且重写authenticate方法classLoginAuth(BaseAuthentication):defauthenticate(self,req......
  • 权限组件及源码分析
    权限组件​ 通过观察APIView的源码,会发现他的里面执行了三个方法self.perform_authentication(request)#认证self.check_permissions(request)#权限self.check_throttles(request)#频率​ 也由此看出,权限是在认证之后执行的权限类的编写写一个类,继承Base......