1、反序列化操作之校验
1.1、标准校验操作流程
- (1)、获取前端传参(字典)
book_info = {"btitle": "三体", "bpub_date": "1999-9-9"}
- (2)、实例化序列化器对象
bs = BookInfoSerializer(data=book_info)
data
参数指定被校验的字典数据
- (3)、启动校验流程
bs.is_valid()
: 默认通过返回值为True或False表示校验成功或者失败;is_valid(raise_exception=True)
: 通过抛出ValidationError
来表示校验失败;
- (4)、校验结果
- 成功:通过
bs.validated_data
获取有效数据 - 失败:通过
bs.errors
获取失败提示信息
- 成功:通过
1.2、校验步骤(经过哪些校验)
-
(1)约束条件校验(见下表)
-
(2)类型校验
-
(3)自定义校验(三种)(针对某一字段进行校验:
validators
、validate_<字段名>
、全字段校验:validate
) -
参数名称 作用 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 -
1.2.2、需求:对书名
btitle
进行名字约束,书名必须包含django
自定义校验一:validators
-
在序列器前面定义函数
check_btitle
,在约束中使用validators=[check_btitle]
j进行调用约束
from rest_framework import serializers
def check_btitle(value):
"""
功能:自定义校验字段btitle
:param value: btitle字段经过前序(约束、类型)校验后的值
:return: 无
"""
if 'django' not in value:
raise serializers.ValidationError('这不是一本关于django的书')
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', min_length=2, validators=[check_btitle])
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
is_delete = serializers.BooleanField(required=False)
image = serializers.ImageField(label='图片', required=False)
- 测试:如果前端传来的值是’三体’,该值没有包含
django
,因此校验失败False
>>> from books_test.serializers import *
>>> book_info = {"btitle": "三体", "bpub_date": "1999-9-9"}
>>> bs = BookInfoSerializer(data = book_info)
>>> bs.is_valid()
False
>>>
自定义校验二:validate_<字段名>
在序列化器里面定义函数def validate_btitle(self, value)
# 重写序列化器特定名称的方法,针对特定字段单独自定义校验,函数名称:validate_<被校验字段名>
def validate_btitle(self, value):
"""
针对btitle自定义校验
:param value: btitle字段经过前序校验的值
:return: 返回经过当前校验的当前字段的值
"""
if "django" not in value:
raise serializers.ValidationError("这不是一本关于django的书")
# 切记,一定要返回字段的有效值,如果不返回会造成当前字段数据丢失
return value
自定义校验三:validate
在序列化器里面定义函数def validate(self, attrs)
# 校验的最终步骤,全字段校验,控制最终有效数据
def validate(self, attrs):
"""
功能:全字段校验
:param attrs: 经过前序校验的所有字段及其值 --> {"btitle": "django精通", "bpub_date": date(1999,9,9)....}
:return: 返回最终的有效数据 就是 validated_data
"""
btitle = attrs.get('btitle')
if 'django' not in btitle:
raise serializers.ValidationError('这不是一本关于django的书')
# 相同方式对别的字段校验...略
# 返回最终的有效数据,如果不返回,后果就是丢失最终的有效数据
return attrs
- 校验流程图示
2、反序列化操作之标准新建/更新操作流程
2.1、新建操作流程
- 在序列化器内重写
create
方法,实现新建
def create(self, validated_data):
"""
功能:基于校验成功的有效数据,新建模型类对象保存数据库
:param validated_data: 最终的有效数据(字典)
:return: 返回新建的模型类对象
"""
instance = BookInfo.objects.create(**validated_data)
return instance
- 终端测试:
>>>from books_test.serializer import *
>>># 1、获取前端传值
>>> book_infoo = {'btitle': '三体', 'bpub_date': '1997-6-6'}
>>># 2、实例化序列化器对象
>>> bs = BookInfoSerializer(data=book_infoo)
>>>#3、启动校验流程(步骤)
>>> bs.is_valid()
True
>>># 4、新建:save()方法本质是间接调用序列化器重写的create方法,自动传入有效数据完成新建
>>> bs.save()
<BookInfo: 三体>
>>>
2.2、更新操作流程
- 在序列化器内重写
update
方法,实现更新(全更新)
setattr()
ORM内置函数作用:更新某一模型类对象
def update(self, instance, validated_data):
"""
功能:更新模型类对象
:param instance: 被更新的模型类对象
:param validated_data:用于更新的有效数据
:return: 返回被更新之后的模型类对象
"""
# 由于有些字段是非必传的,所以我们不确定非必传字段有没有。因此需要for遍历
for field, value in validated_data.items():
setattr(instance, field, value) # setattr():更新指定对象instance数据
instance.save()
return instance
>>> from books_test.serializers import *
>>>#1、获取前端传值
>>> book_infoo = {'btitle': '三体后传', 'bpub_date': '1997-6-6'}
>>># 2、获取被更新对象(书)
>>> book = BookInfo.objects.get(btitle='三体')
>>> # 3、实例化序列化器对象(传入前端传来的值,和被更新的对象)
>>> bs = BookInfoSerializer(data=book_infoo,instance=book)
>>> bs.is_valid()
True
>>># 4、更新
>>> bs.save()
<BookInfo: 三体后传>
>>>
2.3、完整序列化器反序列化操作流程示意图
2.4、补充说明
-
(1)PrimaryKeyRelatedField作用于序列化的时候,把关联对象序列化成主键
-
(2)PrimaryKeyRelatedField作用与反序列化的时候,把主键反序列化成关联的对象;
-
(3)全更新:
全更新其本质是 —— 全校验,必要字段必传必校验。默认情况是全更新 -
(4)部分更新:
部分更新其本质是 —— 部分校验,必要字段可传可不传,传什么就校验什么; -
Serializer(instance=模型类对象,data=参数,partial=True)
: 实例化序列器对象时加上partial=True
表明序列化器后续的校验逻辑为部分校验;
>>> book_infoo = {'bread':100}
>>> book = BookInfo.objects.get(btitle='三体后传')
>>> bs = BookInfoSerializer(data=book_infoo,instance=book,partial=True)
>>> bs.is_valid()
True
>>> bs.save()
<BookInfo: 三体后传>
>>>
- (5)save()方法传递关键字参数
作用:传递的关键字参数,会被合并到validated_data
有效数据中,作用于create
和update
方法!
示例:基于上面的部分更新测试代码,最后一句bs.save()
改成如下代码:
bs.save(bcomment=200, btitle = 三体前传)