写在前面:
'''
序列化器:
实质: 定义了一个叫做 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() 入库保存
- 创建 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() # 保存 数据 到数据库
- 创建 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