drf序列化与反序列化
序列化类常用字段类和字段参数
常用字段类
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)
重点记住几个
CharField
BooleanField
IntergerField
DecimalField
# ListField:{name:'kevin',age:19,hobby:['篮球','足球']}
# DictField:{name:'kevin',age:19,wife:{'name':'刘亦菲','age':33}}
常用字段参数
给CharField字段类使用的参数
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_length | 最小长度 |
allow_black | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
给IntegerField字段类使用的参数
参数名称 | 作用 |
---|---|
max_value | 最小值 |
min_value | 最大值 |
通用参数
放在哪个字段类上都是可以的
参数名称 | 作用 |
---|---|
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认为False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认为False |
序列化类高级用法之source,修改序列化字段名字
source指定的可以是字段;也可以是方法,用于重命名;也可以做跨表查询。
source指定字段
在序列化book表时,name字段在前端显示的时候叫book_name
'在自定义序列化类中使用source字段参数,可以指定序列化表中的那个字段'
book_name=serializers.CharField(source='name')
source指定方法
class BookSerializer(serializers.Serializer):
book_name=serializers.CharField(source='name')
price=serializers.IntegerField()
publish=serializers.CharField(source='publishnb')
class Book(models.Model):
name=models.CharField(max_length=32)
price=models.IntegerField()
publish=models.CharField(max_length=32)
def publishnb(self):
return self.publish+'nb'
source的publishnb
表示表模型的方法
source指定跨表查询
除此之外,source还可以用于跨表查询,直接用orm的基于对象的跨表查询方式
publish_name = serializers.CharField(max_length=8, min_length=3,source='publish.name')
序列化类高级用法之定制序列化字段的两种方式
在序列化类中写SerializerMethodField
表模型
class Book(models.Model):
name=models.CharField(max_length=32)
price=models.IntegerField()
publish=models.ForeignKey(to='Publish',on_delete=models.CASCADE)
class Publish(models.Model):
name=models.CharField(max_length=32)
city=models.CharField(max_length=32)
序列化类
class BookSerializer(serializers.Serializer):
book_name=serializers.CharField(source='name')
price=serializers.IntegerField()
publish=serializers.SerializerMethodField()
# 在序列化类中写
# obj表示当前序列化的对象:book
def get_publish(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city}
在表模型中写方法
表模型
class Book(models.Model):
name=models.CharField(max_length=32)
price=models.IntegerField()
publish=models.ForeignKey(to='Publish',on_delete=models.CASCADE)
def publish_detail(self):
return {'name':self.publish.name,'city':self.publish.city}
class Publish(models.Model):
name=models.CharField(max_length=32)
city=models.CharField(max_length=32)
序列化类
class BookSerializer(serializers.Serializer):
book_name=serializers.CharField(source='name')
price=serializers.IntegerField()
# 要用DictField()序列化字典数据
publish_detail=serializers.DictField()
多表操作之使用在序列化类中自定义序列化字段
使用SerializerMethodField类自定义序列化字段,需要在方法中传入一个obj对象,就是序列化对象,基于此对象进行跨表操作。
'表模型'
class Book(models.Model):
title=models.CharField(max_length=32)
price=models.IntegerField()
pub_date=models.DateField(auto_now_add=True,null=True)
publish=models.ForeignKey("Publish",on_delete=models.CASCADE,null=True)
authors=models.ManyToManyField("Author")
class Publish(models.Model):
name=models.CharField(max_length=32)
city=models.CharField(max_length=32,null=True)
email=models.EmailField(null=True)
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField(null=True)
city=models.CharField(max_length=32,null=True)
'自定义序列化类'
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title=serializers.CharField()
price=serializers.IntegerField()
pub_date=serializers.DateField()
publish=serializers.SerializerMethodField()
authors=serializers.SerializerMethodField()
# obj当前序列化的对象book
# 通过基于对象点的形式跨表查询
def get_publish(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}
# 多对多关系,需要返回列表套字典的形式
def get_authors(self,obj):
author_list=[]
for author in obj.authors.all():
author_list.append({'name':author.name,'age':author.age,'city':author.city})
return author_list
多表操作之在表模型中自定义序列化字段
在表模型中写方法,方法名为序列化类的字段名
'表模型'
class Book(models.Model):
title=models.CharField(max_length=32)
price=models.IntegerField()
pub_date=models.DateField(auto_now_add=True,null=True)
publish=models.ForeignKey("Publish",on_delete=models.CASCADE,null=True)
authors=models.ManyToManyField("Author")
def publish_detail(self):
return {'name':self.publish.name,'city':self.publish.city,'email':self.publish.email}
def author_detail(self):
author_list = []
for author in self.authors.all():
author_list.append({'name': author.name, 'age': author.age, 'city': author.city})
return author_list
class Publish(models.Model):
name=models.CharField(max_length=32)
city=models.CharField(max_length=32,null=True)
email=models.EmailField(null=True)
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField(null=True)
city=models.CharField(max_length=32,null=True)
'自定义序列化类'
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
title=serializers.CharField()
price=serializers.IntegerField()
pub_date=serializers.DateField()
# DictField将字典形式的publish_detail返回的数据进行序列化操作
publish_detail=serializers.DictField()
# ListField()将列表套字典形式的author_detail返回的数据进行序列化操作
author_detail=serializers.ListField()
有关联关系表的反序列化的保存
class BookSerializer(serializers.Serializer):
title=serializers.CharField()
price=serializers.IntegerField()
pub_date=serializers.DateField()
# 序列化
# DictField将字典形式的publish_detail返回的数据进行序列化操作
publish_detail=serializers.DictField(read_only=True)
# ListField()将列表套字典形式的author_detail返回的数据进行序列化操作
author_detail=serializers.ListField(read_only=True)
# 反序列化,需要重新写字段,和序列化字段不一样:前端返回回来的id以及列表
publish=serializers.IntegerField(write_only=True)
authors=serializers.ListField(write_only=True)
# 一定要重写create
def create(self, validated_data):
book_obj=Book.objects.create(
title=validated_data.get('title'),
price=validated_data.get('price'),
pub_date=validated_data.get('pub_date'),
publish_id=validated_data.get('publish'),
)
book_obj.authors.add(*validated_data.get('authors'))
return book_obj
使用继承Serializer的序列化类保存需要重写create方法
缺点
- 在序列化中每个字段要写,无论是序列化还是反序列化
- 如果新增或者修改,在序列化类中都需要重写create或update
解决这个缺陷
使用ModelSerializer来做
补充
在模型类中写逻辑代码,称之为ddd,领域驱动模型
反序列化之数据校验
反序列化的数据校验和forms组件很像,它等于是分为三层校验:
- 字段自己的校验规则
- 局部钩子
- 全局钩子
字段自己的校验规则
如果继承的是Serializer,写法如下:
title=serializers.CharField(max_length=8,min_length=3,error_messages={
'min_length':'书籍名最少为3个字符'
})
如果继承的是ModelSerializer,写法如下:
from rest_framework.serializers import ModelSerializer
from .models import Book
class BookSerializer(ModelSerializer):
class Meta:
model=Book
fields='__all__'
extra_kwargs={
'title':{
'max_length':8,'min_length':3,'error_messages':{
'max_length':'最长8位',
'min_length':'最短3位'
}
}
}
局部钩子
继承Serializer和继承ModelSerializer的写法一样
from rest_framework.exceptions import ValidationError
def validate_title(self,title):
if title=='水浒传':
raise ValidationError('书籍名不能为水浒传')
else:
return title
全局钩子
继承Serializer和继承ModelSerializer的写法一样
def validate(self, attrs): # attrs表示要校验的数据
title=attrs.get('title')
price=attrs.get('price')
if price>80 or len(title)>6:
raise ValidationError('价格不能大于80或者书籍名不能超过6位')
else:
return attrs # 返回校验的数据
模型类序列化器(ModelSerializer)的使用
案例
注意点:
- 自定义序列化字段应加
read_only
参数,这样反序列化的结果无此字段结果集 - 自定义反序列化字段应加
write_only
参数,这样序列化的结果无此字段结果集
使用SerializerMethod自定义ModelSerializer字段
class BookSerializer(serializers.ModelSerializer):
# 不需要写字段了,字段从表模型映射出来
class Meta:
# 要序列化的表模型
model=Book
# 所有字段都要序列化
fields=['title','price','pub_date','publish','authors','publish_detail','author_detail']
extra_kwargs={
'title':{
'max_length':8,'min_length':3,'error_messages':{
'max_length':'最长8位',
'min_length':'最短3位'
},
},
'publish': {
'write_only': True
},
'authors':{
'write_only':True
}
}
publish_detail=serializers.SerializerMethodField(read_only=True)
author_detail=serializers.SerializerMethodField(read_only=True)
def get_publish_detail(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}
def get_author_detail(self,obj):
author_list=[]
for author in obj.authors.all():
author_list.append({'name':author.name,'age':author.age,'city':author.city})
return author_list
以上总结
ModelSerializer的使用步骤详解
- 定义一个类继承ModelSerializer
- 在类内部写内部类
class Meta
- 在内部类指定model:要序列化的表
- 在内部类中指定fields(要序列化的字段,写
__all__
表示所有,不包含方法,写一个个字段) - 在内部类中指定extra_kwargs,给字段添加字段参数的
- 在序列化类中,可以重写某个字段,优先使用你重写的
title=serializers.SerializerMethodField(read_only=True)
def get_title(self,obj):
return '爆款'+obj.title
- 以后不需要重写
create
和update
了
ModelSerializer写好了,兼容性更好,任意表都可以直接存
反序列化数据校验源码分析
反序列化数据校验流程
- 先校验字段自己的规则(根据参数进行校验)
- 局部钩子校验
- 全局钩子校验
反序列化源码分析
注意:在查看源码的时候,我们应注意对象的方法查找顺序,对象点方法,必须先从对象本身逐层往上找
is_vaild
是我们查看反序列化源码的入口,它里面封装了三层校验的方法,必须执行此方法才会走三层校验的f方法:字段校验、局部钩子校验、全局钩子校验。
self.run_validation
,我们通过对象自身查找关系,可以查找到run_validation
在ModelSerializer的父类Serializer中,它里面封装了三层校验的方法:
- 字段校验、局部钩子校验方法:
self.to_internal_value(data)
- 全局钩子校验入口方法:
seif.validate(value)
局部钩子的方法
全局钩子方法
断言assert
由于框架的源码中,大量使用断言,学习一下
断言的定义:断言,作用的判断,断定一个变量必须是xx,如果不是就报错
# 一般写法
name ='xxx'
if name=='xxx':
raise Exception('name不能等于xxx')
...
#assert的断言用法
name='xf'
assert name!='xf','name必=须等于xf'
print('主')