zoukankan      html  css  js  c++  java
  • drf—— 序列化组件

    ----->序列化器-Serializer

    一、序列化组件介绍

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

    二、序列化组件简单使用

    # 序列化的使用
        -写一个序列化类继承serializers.Serializer
        -在类中写要序列化的字段
        -在视图类中,实例化得到一个序列化类的对象,把要序列化的数据传入
            ser=BookSerializer(instance=res,many=True)
        -得到字典
            ser.data就是序列化后的字典

    三、序列化组件使用代码实现

    '''
    5个接口 1. 查询所有 Book--》get 2. 查询单个 BookDetali--》get 3. 新增一个 Book--》post 4. 删除一个 BookDetali--》delete 5. 修改一个 BookDetali--》put '''

    1.查询所有

    url:127.0.0.1.8000/books/  # 注意最后面的 /一定要写

     models.py  # 建立好模型,进行数据迁移,在数据库中手动添加至少2条数据

    from django.db import models
    
    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32,null=True) #测试read_only
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish = models.CharField(max_length=32)

    urls.py   #配置好路由

    path('books/', views.Book.as_view()),

    views.py  #写视图类

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from app01 import models
    from app01.serializer import BookSerializer
    
    class Book(APIView):
        def get(self, request, *args, **kwargs):
            res = models.Book.objects.all()
            # 借助序列化器
            # 如果是多条,就是many=True
            # 如果是单个对象,就不写
            ser = BookSerializer(instance=res, many=True)
            print(type(ser))  # rest_framework.serializers.ListSerializer
            # 通过序列化器得到的字典
            # ser.data
            print(ser.data)
            return Response(ser.data)

    serializer.py  #在app中创建存放序列化器的 类的文件 serializer.py 并写BookSerializer类

    # 序列化器类(序列化Book表)
    # from rest_framework.serializers import Serializer
    from rest_framework import serializers
    from rest_framework.exceptions import ValidationError
    from app01 import models
    
    
    class BookSerializer(serializers.Serializer):
        # 要序列化哪个字段
        id = serializers.IntegerField(required=False)
        # id=serializers.CharField()
        title = serializers.CharField(max_length=32,min_length=2,read_only=True)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        # 序列化的时候看不到,因为write_only=True
       publish = serializers.CharField(max_length=32,write_only=True)

    2.查询单个

    url:127.0.0.1.8000/books/1 #后面的数字代表查询id为几的数据 

    urls.py中加

    re_path('^books/(?P<id>d+)', views.BookDetail.as_view()),

    views.py中加

    class BookDetail(APIView):
        def get(self, request, id):
            res = models.Book.objects.all().filter(id=id).first()
            # 单个,去掉many=True
            # 加many=True和不加,ser不是同一个对象,查单个是BookSerializer对象,查多个是ListSerializer对象,这是由源码中元类决定的
            ser = BookSerializer(instance=res)
            print(type(ser))  # 打印出 app01.serializer.BookSerializer
            return Response(ser.data)

    3.新增一个  ---这里涉及到保存!!!

    ps:新增必须写create方法

    urls.py 不变

    views.py

    class Book(APIView):
        def get(self, request, *args, **kwargs):
            ...
    
        def post(self, request):
            # post提交的数据都在request.data 是个字典
            print(request.data)
            ser = BookSerializer(data=request.data)
            if ser.is_valid():  # 校验数据是否合法
                ser.save()  # 保存到数据库中
                return Response(ser.data)
            else:
                # 没有校验通过的错误信息
                return Response(ser.errors)
    serializer.py
    # 如果序列化类继承的是Serializer,必须重写create方法
    
    class BookSerializer(serializers.Serializer):
        ...
        def create(self, validated_data):
            # 为什么要重写create?为了跟views.py里面的Book表建立关系
            res=models.Book.objects.create(**validated_data)
            print(res)
            return res

    4.修改

    ps:必须写update方法

    urls.py不变

    views.py

    class BookDetail(APIView):
        def get(self, request, id):
            ...
    
        def put(self, request, id):
            # 通过id取到对象
            res = {'code': 100, 'msg': ''}
            try:
                book = models.Book.objects.get(id=id)
                ser = BookSerializer(instance=book, data=request.data)
                ser.is_valid(raise_exception=True)
                ser.save()
                res['msg'] = '修改成功'
                res['result'] = ser.data
    
            except Exception as e:
                res['code'] = 101
                res['msg'] = str(e)
    
            return Response(res)
    serializer.py
    class BookSerializer(serializers.Serializer):
        ...
    
        def update(self, book, validated_data):
            book.title=validated_data.get('title')
            book.price=validated_data.get('price')
            book.publish=validated_data.get('publish')
            book.save()
            return book

    5.删除

    views.py

    class BookDetail(APIView):
        ...
    
        def delete(self,request,id):
            response = {'code': 100, 'msg': '删除成功'}
            models.Book.objects.filter(id=id).delete()
            return Response(response)

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

    # 常用字段类型
        -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    包含错误编号与错误信息的字典

    ---------------------序列化器-------------------------

    五、序列化器的(反序列化之)保存功能

    同三中3.增加一个 里面的保存

    六、序列化器的(反序列化之)字段校验功能

     validators校验,局部钩子,全局钩子

    ps:validators 列表里面可以传多个值进行校验

    # 三种方式
        -字段自己的校验规则(max_length...)
        -validators的校验
            publish = serializers.CharField(max_length=32,validators=[check,])
    
            def check(data):
            if len(data)>10:
                raise ValidationError('最长不能超过10')
            else:
                return data
        -局部和全局钩子
            # 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据
        def validate_title(self, data):
            if data.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return data
        # 全局钩子
        def validate(self, attrs):
            title=attrs.get('title')
            publish=attrs.get('publish')
            if title==publish:
                raise ValidationError('书名不能跟出版社同名')
            else:
                return attrs

    七、序列化类常用字段参数之read_only和write_only

       read_only    表明该字段仅用于序列化输出,默认False
        write_only    表明该字段仅用于反序列化输入,默认False
        
        
        class BookSerializer(serializers.Serializer):
            # 要序列化哪个字段
            id = serializers.IntegerField(required=False)
            # id=serializers.CharField()
            title = serializers.CharField(max_length=32,min_length=2,read_only=True)
            price = serializers.DecimalField(max_digits=5, decimal_places=2)
            # 序列化的时候看不到
            publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)

     八、(反序列化之高级用法之source

    总结:

    1用法一: 修改返回到前端的字段名
        # 若source=title 那么字段名就不能再叫title,这里叫了name
        name = serializers.CharField(max_length=32,min_length=2,source='title')
    2用法二: 如果表模型中有方法
    class Book(models.Model):
        ...
        def test(self):
            # python是强类型语言,不支持字符串和数字直接相加
            return self.title+str(self.price)
        # 执行表模型中的test方法,并且把返回值赋值给xxx
        xxx=serializers.CharField(source='test')
    3用法三: source支持跨表操作
        addr=serializers.CharField(source='publish.addr')
        
    # 可以去看源码,内部如何实现的

    代码:

    urls.py

    models.py

    from django.db import models
    
    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32,null=True) #测试read_only
        price = models.DecimalField(max_digits=5, decimal_places=2)
        # publish = models.CharField(max_length=32)
        #修改后
        publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)
        #这是在测试source第一种方法时加的
        def test(self):
            # python是强类型语言,不支持字符串和数字直接相加
            return self.title+str(self.price)
    
    #新建一张publish表
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        addr=models.CharField(max_length=32)
        #重写__str__
        def __str__(self):
            return self.name

    views.py

    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的名字 ,或 在models.py中重写__str__   
    publish = serializers.CharField(max_length=32,source='publish.name')
    #方法二
        xxx=serializers.CharField(source='test')
    #方法三:跨表
        publish_addr=serializers.CharField(source='publish.addr')

    九、模型类序列化器

    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

    #方式一:Serializer
    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
    
    #方式二:ModelSerializer
    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__'

    十一、序列化组件源码分析

    #序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
    #序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
    #Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
    #再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
    #当参数传过去,判断是方法就加括号执行,是属性就把值取出来
  • 相关阅读:
    js学习笔记之标准库
    js学习笔记
    html5学习
    C#调用win32 api程序实例
    javascript计算字符串中出现最多的字符和个数
    javascript中的promise和deferred:实践(二)
    jquery animate 详解
    jquery animate stop函数解析
    javascript继承的写法
    css3 改变滚动条样式
  • 原文地址:https://www.cnblogs.com/guojieying/p/13928342.html
Copyright © 2011-2022 走看看