美文网首页
五、DRF之序列化器

五、DRF之序列化器

作者: battleMonkey | 来源:发表于2019-03-24 12:43 被阅读0次

    写在前面:

    '''
    序列化器:
    实质: 定义了一个叫做 xx序列化器 的 <类>,  
    作用: 
         1. 实现 <json> 和 <对象> 的相互转化
         2. 实现对 前端数据 的校验功能 
    序列化       读取(read_only) 数据库         obj(数据库)   ->       json
    反序列化     写入 (write_only) 数据库            json      ->     obj(数据库)
    '''
    

    1. 定义创建序列化类( 子应用中,新建 serializers.py)

    from rest_framework import serializers
    
    # 新建 BookInfoSerializer 序列化器
    class BookInfoSerializer(serializers.Serializer):   # 记得 Serializer 的 "S" 大写
        id = serializers.IntegerField(read_only=True)
        
        # validators 定义 name 采用 自定义的 custom_validate 验证方式
        name = serializers.CharField(max_length=20, label='名字', validators=[custom_validate])
        
        pub_date = serializers.DateField(required=False)
        readcount = serializers.IntegerField(required=False)
        commentcount = serializers.IntegerField(required=False)
        
        # 设置标记删除状态为 write_only=True, 因为 我不需要返回给前端 是否删除标记
        is_delete = serializers.BooleanField(write_only=True, required=False)
        image = serializers.ImageField(write_only=True, required=False)
        
        # 设置 隐藏字段 | 获取书籍包含的 所有 英雄 有 多个, 所以添加 many=True
        peopleinfo_set = serializers.StringRelatedField(many=True, required=False)
    
    
    # 新建 PeopleInfoSerializer 序列化器
    class PeopleInfoSerializer(serializers.Serializer):
        """人物数据 序列化器"""
        GENDER_CHOICES = (
            (0, 'male'),
            (1, 'female')
        )
        id = serializers.IntegerField(label='ID', read_only=True)
        name = serializers.CharField(label='名字', max_length=20)
        gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
        description = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
        
        # 详见 下方的 外键:
        
        # book = serializers.PrimaryKeyRelatedField(read_only=True)
        # book = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())
        # book = serializers.StringRelatedField()
        book = BookInfoSerializer()
    
    

    2. 设置 隐藏字段

    • 获取书籍包含的 所有 相关人物 有 多个, 需要添加参数 many=True
    peopleinfo_set = serializers.StringRelatedField(many=True)  
    

    3. 序列化器的外键 配置

    3.1 外键两种方法显示: <模型对象> -> 显示 模型对象id
    # 1.1 需设置 read_only=True, 即 不能 通过此 参数 存入 book数据 到数据库
    book = serializers.PrimaryKeyRelatedField(read_only=True)
    或
    # 1.2 将 相关 数据 都给予 queryset
    book = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())
    
    • 包含read_only=True参数时,该字段将不能用作反序列化使用
    • 包含queryset参数时,将被用作反序列化时参数校验使用
    3.2 外键显示: <模型对象> -> 显示 __str__ 指定的 字符串
    # 2. StringRelatedField 指向了 模型所对应的 __str__ 方法
    book = serializers.StringRelatedField()
    
    3.3 外键显示: <模型对象> -> 显示<对象模型>所有属性参数
    # 3. 使用关联对象的序列化器 
    book = BookInfoSerializer() # 相当于 把 <book对象模型> 给予了 BookInfoSerializer 这个序列化器
    

    4. 测试

    4.1 序列化
    • 从数据库获取对象
    person = PeopleInfo.objects.get(id=1)
    
    • 将对象 传给 序列化器
    serializer = PeopleInfoSerializer(person)
    
    • 获取序列化数据
    serializer.data
    
    {
        'id': 1, 
        'name': '郭靖', 
        'gender': 1, 
        'description': '降龙十八掌', 
        'book': OrderedDict([
            ('id', 1), 
            ('name', '射雕英雄传'), 
            ('pub_date', '1980-05-01'), 
            ('readcount',12), 
            ('commentcount', 34), 
            ('is_delete', False), 
            ('image', None), 
            ('peopleinfo_set', ['郭靖', '黄蓉', '黄药师', '欧阳锋', '梅超风'])
         ])
     }
    
    4.2 反序列化
    4.2.1 数据校验(在终端执行 python manage.py shell,进行验证)
    • 导入序列化器
    from books.serializers import BookInfoSerializer
    
    • 假拟 一个 前端 传来的 数据 data
    data = {      
        'name': 'itcast',
        'pub_date':'abdc',
        'commentcount':20,
        'readcount':50
    }
    
    • data: 把 前端 传来的数据 给 序列化器
    serializer = BookInfoSerializer(data=data)  
    
    • 校验数据
    # 验证成功返回 True,否则返回 False
    serializer.is_valid()
    
    # 显示报错信息
    serializer.errors # 显示报错信息
    
    '''
    参数: raise_exception=True
    在验证失败时抛出异常serializers.ValidationError, 
    REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
    '''
    serializer.is_valid(raise_exception=True) 
    
    4.2.2 三种自定义验证的方法(在 要验证的类里 定义 方法)
    • 单个字段 个性化验证 (记得 返回 value)
    class BookInfoSerializer(serializers.Serializer):
    
    '''省略'''
    
        def validate_readcount(self, value):    # validate_要验证的字段名
            if value < 0:
                raise serializers.ValidationError("数据不能小于0")
                
            return value                       # 记得 返回 value
    
    • 多个字段 之间的验证 (记得 返回 attrs)
    class BookInfoSerializer(serializers.Serializer):
    
    '''省略'''
    
        def validate(self, attrs):
            # attrs 就是 那个 data
            # serializer = BookInfoSerializer(data=data)
            # 即 attrs = data
            commentcount = attrs.get("commentcount")
            readcount = attrs.get("readcount")
            if readcount < commentcount:
                raise serializers.ValidationError('评论量,不能大于阅读量')
    
            return attrs        # 记得 返回 attrs
    
    • validators自定义验证 的使用 (记得在 对应属性 通过validators=[custom_validate] 调用)
    class BookInfoSerializer(serializers.Serializer):
    
    '''省略, 使用场景: 禁止 用户 用 "admin" 这个用户名 注册'''
        
        # 谁调用这个函数方法, self 就是谁, 
        # 这里 name 对 它 进行了 调用 所以 这里的self 就是 name
        def custom_validate(self):
            if self == "admin":
                raise serializers.ValidationError('请不要使用admin来注册')
                
        # 调用: validators 定义 name 采用 自定义的函数方法 custom_validate 验证     
        name = serializers.CharField(max_length=20, label='名字',validators=[custom_validate])
    
    
    4.2.3 serializer.save() 入库保存
    1. 创建 create 方法, 实现 save() 的使用

    (Serializer不具有.save需要的create()方法, 需要自行创建)

    class BookInfoSerializer(serializers.Serializer):
    
    '''
    1. 当我们的序列化器继承自 serializer.Serializer的时候
    2. 当我们需要自己实现 序列化器的 create 方法, 实现create方法的目的:  实现 数据的保存操作
    '''
          
        def create(self, validated_data):
            # validated_data
            # 验证之后的数据
            # 如果 我们在序列化器初始化的时候 传递的 data, 经过我们的校验之后
            # 完全符合验证规则时 那么 validated_data = data
            """
            validated_data = {
                'name': 'ppx',
                'pub_date': 'abdc',
                'commentcount': 2,
                'readcount': 10
            }
            """
            book = BookInfo.objects.create(**validated_data)        # 利用 解包, 传入对应的键值对
            return book         # 记得必须返回 book对象
    
    • 注意: 写入数据库前 必须先验证, 否则会报错 (在终端执行 python manage.py shell,进行验证)
    from books.serializers import BookInfoSerializer
    from books.models import BookInfo
    data = {
        'name': 'python',
        'pub_date': '1998-12-22',
        'commentcount': 2,
        'readcount': 10
    }
    
    serializer = BookInfoSerializer(data=data)  # 调用 序列化器, 进行 反序列化
    serializer.is_valid()                       # 校验 参数
    serializer.save()                           # 保存 数据 到数据库
    
    1. 创建 update() 方法, 实现执行 serializer.save() 进行更新操作

    (Serializer不具有serializer.save()需要的update()方法, 需要自行创建)

    class BookInfoSerializer(serializers.Serializer):
    
    '''省略'''
        
        def update(self, instance, validated_data):
            # instance 序列化器中 初始化传递过来的模型对象
            # validated_data:
            # 如果我们在序列化器初始化的时候 传递的 data, 经过我们的验证之后
            # 完全符合验证规则的时候, validated_data = data
    
            instance.name = validated_data.get('name', instance.name)
            instance.pub_date = validated_data.get('pub_date', instance.pub_date)
            instance.readcount = validated_data.get('readcount', instance.readcount)
            instance.commentcount = validated_data.get('commentcount', instance.commentcount)
    
            # 模型的数据发生变化后, 需要调用模型对象的 save 方法
            instance.save()
    
            # 更新数据完成之后 要返回 实例对象
            return instance
    

    在终端执行 python manage.py shell,进行验证

    data = {
        "id":1,
        'name': 'ppx',
        'pub_date': 'abdc',
        'commentcount': 2,
        'readcount': 10
    }
    
    book = BookInfo.objects.get(id=data.get("id"))  # 通过前端 传过来的 书籍id, 获取书籍对象
    
    # 同时传入instance和data 即视为 更新操作
    serializer = BookInfoSerializer(instance=book, data=data) 
    serializer.is_valid()                           # 校验参数
    
    serializer.save()                               # 保存数据
    

    两点说明:
    1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

    serializer.save(owner=request.user)
    

    2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新

    serializer = BookInfoSerializer(instance=book, data={'pub_date': '2999-1-1'}, partial=True)
    

    5. 使用ModelSerializer – 继承自 类Serializer

    5.1在 serializer.py模块 新建 对应序列化器类 继承类ModelSerializer

    划重点 :关联模型类
    model = BookInfo !
    model = BookInfo !
    model = BookInfo !
    是关联 <模型类>, 不是 <查询集> 不是BookInfo.query.all() # 大兄弟...!!!

    '''
    ModelSerializer 和 Serializer 的区别
    1. ModelSerializer 是继承自 Serializer
    2. ModelSerializer 自动帮我们 生成字段(根据模型类自动生成)
    3. ModelSerializer 自动帮我们 实现了 create()方法 和 update()方法
    4. ModelSerializer 必须 有 model
    '''
    from rest_framework import serializers
    from books.models import BookInfo
    
    
    class BookInfoModelSerializer(serializers.ModelSerializer):
        class Meta:
            # 1. 关联模型类
            model = BookInfo
            
            # 2. # 默认为 模型所有字段
            fields = '__all__'  
            
            # 3. 自定义显示指定某些字段
            # fields = ['id', 'name', 'pub_date'] 
            
            # 4. 不包含 某些字段
            exclude = ['is_delete']                
            
            # 5. 修改自动生成字段的 选项 信息
            extra_kwargs= {                     
                # 字段名: {选项: 选项值}
                'pub_date': {'required': True},
                'readcount': {
                    'max_value': 100,
                    'min_value': 1
                }
            }
            
            # 6. 设置以下这些字段为只读属性
            # read_only_fields = ['id', 'name', 'pub_date'] 
            
    
    • 注意: 修改属性, 都是在 class Meta: 里面写的 model、 fields、exclude、extra_kwargs、read_only_fields

    相关文章

      网友评论

          本文标题:五、DRF之序列化器

          本文链接:https://www.haomeiwen.com/subject/qpfuvqtx.html