• Django-序列化器


    一、序列化组件介绍

    作用:
        1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
        	-Book--序列化器-->字典--同过drf:Response--》json格式字符串--->传给前端
        2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
        	json格式数据---drf:Request-->字典---序列化器---》Book
        3. 反序列化,完成数据校验功能
    

    二、序列化组件简单使用

    序列化的使用如下:

    1 新建一个py文件,写一个类继承serializers下的Serializer类
    from rest_framework import serializers
    
    2 在类中写要序列化的字段,比如
    class BookSerializer(serializers.Serializer):
        id=serializers.IntegerField()
        title=serializers.CharField(max_length=32)
        price=serializers.DecimalField(max_digits=5, decimal_places=2)
        publish=serializers.CharField(max_length=32)
        
    3 在视图类中,实例化得到一个序列化类的对象,把要序列化的数据传入
    ser=BookSerializer(instance=res,many=True)  # 如果是queryset对象就需要many参数,单对象就不需要
    
    4 得到字典
    ser.data就是序列化后的字典
    

    根据restful规范,我们一般根据请求方式来确实要实现的功能。如get请求是查询,post请求是新增,delete请求是删除,put或者patch请求是修改。

    三、序列化类字段类型和字段参数

    # 字段类型(记列的这几个)
    	-IntegerField
        -CharField
        -DecimalField
        -DateTimeField
        -。。。跟models中大差不差
        
    # 常用字段参数
    	-选项参数
            max_length	最大长度
            min_lenght	最小长度
            allow_blank	是否允许为空
            trim_whitespace	是否截断空白字符
            max_value	最小值
            min_value	最大值
        
        -通用参数
        	#重点
            read_only	表明该字段仅用于序列化输出,默认False
            write_only	表明该字段仅用于反序列化输入,默认False
            
            # 掌握
            required	表明该字段在反序列化时必须输入,默认True
            default	    反序列化时使用的默认值
            allow_null	表明该字段是否允许传入None,默认False
            
            # 了解
            validators	该字段使用的验证器
            error_messages	包含错误编号与错误信息的字典
        
    	
    

    四、序列化器的保存功能

    当我们需要新增或者修改对象时候,必须要重写create和update方法,不然序列化器不知道要往哪张表里存

    重写create方法

    # 视图类
    def post(self, request):
        print(request.data)
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()  # 保存到数据库中
            return Response(ser.data)
        else:
            # 没有校验通过的错误信息
            return Response(ser.errors)
    # 序列化类  
    class BookSerializers(serializers.Serializer):
        def create(self, validated_data):
            res=models.Book.objects.create(**validated_data)
            return res
    

    重写update方法

    # 视图类
    def put(self,request,pk,*args,**kwargs):
        old_obj = models.Book.objects.filter(pk=pk).first()
        ser = myserializers.BookSerializers(instance=old_obj,data=request.data,partial=False)
        if ser.is_valid():
            obj = ser.save()
            return Response({
                'status':0,
                'msg':'ok',
                'results':myserializers.BookSerializers(obj).data
            })
        else:
            return Response(ser.errors)
    # 序列化类
    class BookSerializers(serializers.Serializer):
        def update(self, instance, validated_data):
            # 先获得要修改属性
            title = validated_data.get('title')
            publish = validated_data.get('publish')
            price = validated_data.get('price')
    		# 修改属性
            instance.title=title
            instance.publish=publish
            instance.price=price
            # 存属性
            instance.save()
            return instance
    

    五、序列化器的字段校验功能

    1.局部钩子,和form组件的局部钩子一样,不过方法名字是validate_字段名

    2.全局钩子,和form组件的全局钩子一样,不过方法名字是validate

    3.自定义检测规则

    # 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据
        def validate_title(self, data):
            if data.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return data
            
    # 全局钩子,属性从attrs里拿
        def validate(self, attrs):
            title=attrs.get('title')
            publish=attrs.get('publish')
            if title==publish:
                raise ValidationError('书名不能跟出版社同名')
            else:
                return attrs
            
    # 自定义检测规则,首先自己写一个方法,需要一个data参数,然后在要检测的字段中,加入validators属性,等于一个列表
    def check(data):
        if len(data)>10:
            raise ValidationError('最长不能超过10')
        else:
            return data
    publish = serializers.CharField(max_length=32,validators=[check,])  # 自定义检验这个字段,可以写多个检验方法
    

    六、高级用法之source

    1 修改返回到前端的字段名
    	# source=title    字段名就不能再叫title
    	name = serializers.CharField(max_length=32,min_length=2,source='title')
    2 如果表模型中有方法
    	# 执行表模型中的test方法,并且把返回值赋值给xxx
    	xxx=serializers.CharField(source='test')
    3 sourc支持跨表操作
    	addr=serializers.CharField(source='publish.addr')
    

    1.1source源码分析

    大致实现思路是,先按照点切割,然后看切割出来的字符串是不是可调用(即有没有call魔术方法),如果不可调用,直接去表模型里把字段反射出来,如果可调用,那就加括号执行,如果是多个字符串,比如publish.author.name,那么就for循环一层一层的重复上述过程

    source是CharField的一个参数,所以由CharField入口,CharField继承了Field类,在该类的初始化方法中找到了source参数
    

    image-20201105152215362

    使用source时候,属性名不能等于source的值

    image-20201105152651201

    image-20201105152923399

    image-20201105153031697

    image-20201105153217257

    image-20201105153409400

    七、模型类序列化器

    1 原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系
    
    2 使用
    	class BookModelSerializer(serializers.ModelSerializer):
            class Meta:
                model=表模型    # 跟哪个表模型建立关系
                fields=[字段,字段] # 序列化的字段,反序列化的字段
                fields='__all__' # 所有字段都序列化,反序列化
                exclude=[字段,字段] # 排除哪些字段(不能跟fields同时使用)
                read_only_fields=['price','publish']  # 序列化显示的字段
    			write_only_fields=['title']           # 反序列化需要传入的字段
                extra_kwargs ={'title':{'max_length':32,'write_only':True}}
                depth=1  # 了解,跨表1查询,最多建议写3
            # 重写某些字段
            publish = serializers.CharField(max_length=32,source='publish.name')
            # 局部钩子,全局钩子,跟原来完全一样
    3 新增,修改
    	-统统不用重写create和update方法了,在ModelSerializer中重写了create和update
    

    八、SerializerMethodField

    SerializerMethodField是一种比较简单的序列器使用方法,以下例子要实现在book返回的数据中,还要拿到publish表中的对应id的所有字段。

    # 以下是我们之前使用的类,字段太多,写起来麻烦
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        name = serializers.CharField(max_length=32,min_length=2,source='title')
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        publish = serializers.SerializerMethodField()
        def get_publish(self,obj):
            dic={'name':obj.publish.name,'addr':obj.publish.addr}
            return dic
    
        
    # 利用SerializerMethodField,大大简化了写法,且能实现同样的功能
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = '__all__'
        publish = serializers.SerializerMethodField()
        def get_publish(self,obj):
            dic={'name':obj.publish.name,'addr':obj.publish.addr}
            return dic
        
        
        
    ## 第三种方案,使用序列化类的嵌套
    class PublishSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Publish
            # fields = '__all__'
            fields = ['name','addr']
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        publish = PublishSerializer()
    
        class Meta:
            model = models.Book
            fields = '__all__'
    

    注意:

    SerializerMethodField
    	-写在Serializer中
            publish = serializers.SerializerMethodField()
            def get_publish(self,obj):
        -这个不可以被反序列化
        	在Serializer中写两字段,一个作为序列化字段,一个作为反序列化字段,比如
            publish1 = serializers.SerializerMethodField(read_only = True)
            publish2 = serializers.SerializerMethodField(write_only = True)
    

    九、drf的请求与相应

    # Request
    -data :前端以post请求提交的数据都在它中
    -FILES :前端提交的文件
    -query_params:就是原来的request.GET
    -重写了 __getattr__
    -使用新的request.method其实取得就是原生request.method(通过反射实现)
            
    # Response
    -from rest_framework.response import Response
    -data:响应的字典
        -status:http响应的状态码
        -drf提供给你了所有的状态码,以及它的意思
        from rest_framework.status import HTTP_201_CREATED
        -template_name:模板名字(一般不动),了解
        -headers:响应头,字典
        -content_type:响应的编码方式,了解
        
    # 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
    	-配置文件方式(全局)
            -如果没有配置,默认有浏览器和json
                -drf有默认配置文件
                from rest_framework.settings import DEFAULTS
                REST_FRAMEWORK = {
                'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
                    'rest_framework.renderers.JSONRenderer',  # json渲染器
                    'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
                )
            	}
        -在视图类中配置(局部)
        	-粒度更小
            -class BookDetail(APIView):
        		renderer_classes=[JSONRenderer,]
    

    十、many=True源码分析,局部全局钩子源码解析

    1.many源码分析

    在我们使用群增,群该等操作,会加上many=True。

    many是is_valid的参数,由is_valid进入,一路找到了BaseSerializer的new魔术方法

    image-20201105154502716

    image-20201105160454751

    2.局部钩子与全局钩子源码

    2 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data)
    	-Serializer这个类的:self.run_validation
        
    def run_validation(self, data=empty):
        # 省略部分代码
            value = self.to_internal_value(data)  # 局部字段自己的校验和局部钩子校验
            try:
                self.run_validators(value)
                value = self.validate(value)  # 全局钩子的校验
            except (ValidationError, DjangoValidationError) as exc:
                raise ValidationError(detail=as_serializer_error(exc))
            return value
    
  • 相关阅读:
    Python 语音识别
    Python 无法安装PyAudio问题
    webRTC脱坑笔记(四)— windows下Nginx对Node服务的反向代理
    webRTC脱坑笔记(三)— webRTC API之RTCPeerConnection
    webRTC脱坑笔记(二)— webRTC API之MediaStream(getUserMedia)
    webRTC脱坑笔记(一)— 初识webRTC
    StringBuffer
    字符串的反转
    数组的反转
    String
  • 原文地址:https://www.cnblogs.com/chiyun/p/14066486.html
Copyright © 2020-2023  润新知