五、DRF之序列化器

写在前面:

'''
序列化器:
实质: 定义了一个叫做 xx序列化器 的 <类>,  
作用: 
     1. 实现  和 <对象> 的相互转化
     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() # 相当于 把  给予了 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之序列化器)