序列化组件之Serializer类
目录
在编写接口进行前后台数据交互时,一定会通过django的ORM来进行数据查询,那么就会有一个问题。
将查询出来的query_set对象转换为Json数据格式返回回去。
Django REST framework针对序列化问题给我们提供了序列化类方便我们实现自己的序列化和反序列化器。
一、基于Serializer类实现序列化器
例如,我们以及有了一个数据库模型类User
class User(models.Model):
sex_choice = ((0,"男"),(1,"女"))
name = models.CharField(max_length=32,unique=True)
age = models.IntegerField(null=True)
height = models.DecimalField(max_digits=5,decimal_places=2,null=True)
sex = models.IntegerField(choices=sex_choice,default=0)
icon = models.ImageField(upload_to="icon",default="default.png")
pwd = models.CharField(max_length=32,null=True)
1.1 实现序列化组件
- 在任意位置新建.py文件,实现相关组件
'''serializers.py'''
# 导入序列化组件
from rest_framework import serializers
# 继承Serializer类实现序列化组件
class UserSerializer(serializers.Serializer):
# 这里的序列化字段必须在model的字段中存在
# 如果要参与序列化,名字一定要与model的属性同名
# 如果不参与序列化的model属性,在序列化类中不做声明
name = serializers.CharField()
age = serializers.IntegerField()
height = serializers.DecimalField(max_digits=5,decimal_places=2)
# 如果直接这么写,序列化的就是记录对应的字段,就是0/1,因此要自定义序列化字段
# sex = serializers.IntegerField()
# 自定义序列化字段,序列化的属性值由方法来提供,
# 方法的名字:固定为 get_属性名,
# 方法的参数:序列化对象,序列化的model对象
# 强烈建议自定义序列化字段名不要与model已有的属性名重名
gender = serializers.SerializerMethodField()
def get_gender(self,obj):
return obj.get_sex_display()
1.2 使用序列化组件
- 实例化自己的序列化组件。用于序列化时,将模型类对象传入instance参数,many为True表示有多个对象需要序列化。
- 序列化后的数据都保存在,序列化对象的.data中
'''views.py'''
from . import models
from .utils import serializers
class UserAPIView(APIView):
def get(self,request,*args,**kwargs):
pk = kwargs.get("pk")
# 单查询
if pk:
# ORM操作数据库拿到资源数据
user_obj = models.User.objects.filter(pk=pk).first()
if not user_obj:
return Response({
"status": 1,
"msg" : "单查 error"
})
# 格式化成能返回给前台的数据(序列化) many表示是否有多个对象
user_ser = serializers.UserSerializer(user_obj, many=False)
# 返回格式化后的数据
user_data = user_ser.data # .data就是格式化后的数据
return Response({
"status":0,
"msg": "单查 ok",
"results": user_data
})
# 群查询
else:
user_query = models.User.objects.all()
#many表示是否有多个对象
user_list_data = serializers.UserSerializer(user_query, many=True).data
return Response({
"status": 0,
"msg": "群查 ok",
"results": user_list_data
})
1.3 常用字段类型及参数
常用字段类型:
字段 | 字段构造方式 |
---|---|
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(max_length=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=) |
选项参数:
参数名称 | 作用 |
---|---|
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 |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
二、基于Serializer类实现反序列化器
- 当需要序列化的时候使用序列化器,反序列化时使用反序列化器
2.1 实现反序列化组件
- error_messages表示自定义错误信息
- required表示True就是校验该字段,False就是不校验该字段
'''serializers.py'''
# 导入序列化组件
from rest_framework import serializers
# 继承Serializer类实现反序列化组件
class UserDeserializer(serializers.Serializer):
# 系统校验规则
# 系统必须反序列化的字段
# 序列化属性名不是必须与model属性名对应,但是与之对应会方便序列化将校验通过的数据与数据库进行交互
name = serializers.CharField(min_length=3, max_length=64,error_messages={
'required': '姓名必填',
'min_length': '太短',
})
pwd = serializers.CharField(min_length=3, max_length=64)
# 系统可选的反序列化字段:没有则不校验,required=False表示不校验,True就是校验
age = serializers.IntegerField(min_value=0, max_value=150, required=False)
# 自定义反序列化字段:一定参与校验,且要在校验过程中,将其从入库的数据中取出,剩余与model对应的数据才会入库
re_pwd = serializers.CharField(min_length=3, max_length=64)
2.2 使用反序列化组件
- 实例化反序列化组件需要指定参数data。表明是反序列化
- is_valid()判断校验是否全部通过,raise_exception参数如果设置True,如果校验不成功就直接抛错
- save()方法会执行create和update方法需要自己去实现
- 反序列化对象的.errors是反序列化的错误信息
'''views.py'''
from . import models
from .utils import serializers
from rest_framework import status
class UserAPIView(APIView):
# 单增
def post(self,request,*args,**kwargs):
# 从请求对象中拿到前台的数据
# 校验前台数据是否合法
# 反序列化成后台Model对象与数据库交互
request_data = request.data
# 反序列化目的:封装数据的校验过程,以及数据库交互的过程
# 反序列化传入data
user_ser = serializers.UserDeserializer(data=request_data)
# 调用反序列化的校验规则:系统规则,自定义规则(局部钩子,全局钩子)
result = user_ser.is_valid() # raise_exception 如何设置为True,则校验不成功会直接帮你抛错
if result:
# 校验通过,可以与数据库进行交互:增(create),改(update)
user_obj = user_ser.save() # save()方法会执行create和update方法需要自己实现
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.UserSerializer(user_obj).data
})
else:
# 校验失败,返回错误信息
return Response({
'status': 1,
'msg': user_ser.errors # 反序列化的错误信息
}, status=status.HTTP_400_BAD_REQUEST)
2.3 局部钩子和全局钩子
局部钩子:
- validate_字段名(self, 字段值)
- 成功返回value,失败抛异常
# 继承Serializer类实现反序列化组件
class UserDeserializer(serializers.Serializer):
# 局部钩子:validate_字段名(self, 字段值)
# 规则:成功返回value,失败抛异常
def validate_name(self,value):
if 'g' in value.lower():
raise serializers.ValidationError('名字中不能有g')
return value
全局钩子:
- validate(self, 所有校验的数据字典)
- 成功返回attrs,失败抛异常
# 继承Serializer类实现反序列化组件
class UserDeserializer(serializers.Serializer):
def validate(self, attrs):
# 取出联合校验的字段们:需要入库的值需要拿到值,不需要入库的需要从校验字段中取出
pwd = attrs.get('pwd')
re_pwd = attrs.pop('re_pwd')
if pwd != re_pwd:
raise serializers.ValidationError({'re_pwd': '两次密码不一致'})
return attrs
2.4 重写Create方法,实现添加数据库数据
- 当save是,就会调用该方法,将校验后的数据保存到数据库中,返回query_set对象
# 继承Serializer类实现反序列化组件
class UserDeserializer(serializers.Serializer):
def create(self, validated_data):
from .. import models
return models.User.objects.create(**validated_data)
2.5 得到序列化抛出的错误信息内容
# 得到序列化抛出的错误信息内容
msg = list(ser_obj.errors.values())[0][0]
return APIResponse(1, msg)