zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    LeetCode Missing Number (简单题)
    LeetCode Valid Anagram (简单题)
    LeetCode Single Number III (xor)
    LeetCode Best Time to Buy and Sell Stock II (简单题)
    LeetCode Move Zeroes (简单题)
    LeetCode Add Digits (规律题)
    DependencyProperty深入浅出
    SQL Server存储机制二
    WPF自定义RoutedEvent事件示例代码
    ViewModel命令ICommand对象定义
  • 原文地址:https://www.cnblogs.com/chiyun/p/14066486.html
Copyright © 2011-2022 走看看