序列化,是指将复杂的QuerySet和Model类型转换成Python基本数据类型,从而将这些基本数据类型以JSON的形式响应给客户端。
反序列化则和序列化相反,是指将Http请求中传入的JSON数据转换成复杂的数据类型,从而保存在数据库中。
在REST Framework中,提供了多个用于序列化操作的类,但常用的也就如下两个:
使用时需要导入对应模块:
from rest_framework import serializers
接下来我们就分别看看这两个序列化操作的类。
Serializer进行序列化的基本格式如下:
class UserInfoSerializer(serializers.Serializer):
id = serializers.CharField(read_only=True)
username = serializers.CharField(min_length=3, max_length=20, error_messages={'required': '该字段必填'})
img = serializers.ImageField(required=False)
nick_name = serializers.CharField(max_length=20)
address = serializers.CharField(max_length=255)
xxx = serializers.SerializerMethodField(read_only=True)
class Meta:
model = User
# 自定义显示 多对多 字段
def get_xxx(self, row):
'''row: 传过来的正是 User表的对象'''
users = row.username # 获取用户名
return users
# 定义创建语法:ser.save()执行,就会立刻调用create方法用来创建数据
def create(self, validated_data):
'''validated_data: 表单或者vue请求携带的json:
{"username":"zhangsan","password":"123456"}'''
# https://www.cnblogs.com/xiaonq/p/7978409.html
return User.objects.create(**validated_data)
# 定义更新方法
def update(self, instance, validated_data):
'''
instance : 查询的对象
validated_data : postman提交的json数据
{"username":"zhangsan","password":"123456"}
'''
if validated_data.get('username'):
instance.username = validated_data['username']
instance.save()
return instance
# 定义单一字段验证的方法
def validate_name(self, value):
if value == 'root':
raise serializers.ValidationError('不能创建root管理员账号')
return value
# 定义多字段验证方法
def validate(self, attrs):
print(attrs)
if attrs.get("username") == 'admin':
raise serializers.ValidationError('不能创建admin用户')
return attrs
这个序列化类中有两部分:
整个序列化类的实现就这么简单
关于DRF的View相关部分会在之后的文章中详细总结。
在调用serializer.save()时,会创建或者更新一个Model实例(调用create()或update()创建),具体根据序列化类的实现而定,如:
# .save() will create a new instance.``serializer ``=` `StudentSerializer(data``=``data)` `# .save() will update the existing `comment` instance.``serializer ``=` `StudentSerializer(comment, data``=``data)
Serializer中的create()和update()方法用于创建生成一个Model实例,在使用Serializer时,如果要保存反序列化后的实例到数据库,则必须要实现这两方法之一,生成的实例则作为save()返回值返回。方法属性validated_data表示校验的传入数据。
当反序列化时,在调用Serializer.save()之前必须要使用is_valid()方法进行校验,如果校验成功返回True,失败则返回False,同时会将错误信息保存到serializer.errors属性中。
serializer.data中保存了序列化后的数据。
当serializer.is_valid()进行校验后,如果校验失败,则将错误信息保存到serializer.errors属性中。
在定义Model时,我们通过models.获取了各种不同的字段,作为数据库中表的一个列。而在Serializer中,也需要通过`serializers.的形式获取对应Model的字段,用来在JSON数据和Python数据类型之间进行转换,此外还可以根据Field中传入的属性进行校验、设置默认值。以下对常用Serializer的Field进行整理。
使用时,需要导入所在模块:
from rest_framework import serializers
对应models.CharField,同时如果指定长度,还会负责校验文本长度。
max_length:最大长度;
min_length:最小长度;
allow_blank=True:表示允许将空串做为有效值,默认False;
对应models.EmailField,验证是否是有效email地址。
对应models.IntegerField,代表整数类型
对应models.FloatField,代表浮点数类型
对应models.DateTimeField,代表时间和日期类型。
format=‘YYYY-MM-DD hh:mm’:指定datetime输出格式,默认为DATETIME_FORMAT值。
需要注意,如果在 ModelSerializer 和HyperlinkedModelSerializer中如果models.DateTimeField带有auto_now=True或者auto_add_now=True,则对应的serializers.DateTimeField中将默认使用属性read_only=True,如果不想使用此行为,需要显示对该字段进行声明:
class` `CommentSerializer(serializers.ModelSerializer):`` ``created ``=` `serializers.DateTimeField()` ` ``class` `Meta:`` ``model ``=` `Comment
对应models.FileField,代表一个文件,负责文件校验。
max_length:文件名最大长度;
allow_empty_file:是否允许为空文件;
对应models.ImageField,代表一个图片,负责校验图片格式是否正确。
max_length:图片名最大长度;
allow_empty_file:是否允许为空文件;
如果要进行图片处理,推荐安装Pillow: pip install Pillow
这是serializers中特有的Field,它不根据用户提交获取值,而是从默认值或可调用的值中获取其值。一种常见的使用场景就是在Model中存在user_id作为外键,在用户提交时,不允许提交user_id,但user_id在定义Model时又是必须字段,这种情况下就可以使用HiddenField提供一个默认值:
class` `LeavingMessageSerializer(serializers.Serializer):` ` ``user ``=` `serializers.HiddenField(`` ``default``=``serializers.CurrentUserDefault()`` ``)
所谓公共参数,是指对于所有的serializers.都可以接受的参数。以下是常见的一些公共参数。
read_only=True表示该字段为只读字段,即对应字段只用于序列化时(输出),而在反序列化时(创建对象)不使用该字段。默认值为False。
write_only=True表示该字段为只写字段,和read_only相反,即对应字段只用于更新或创建新的Model时,而在序列化时不使用,即不会输出给用户。默认值为False。
required=False表示对应字段在反序列化时是非必需的。在正常情况下,如果反序列化时缺少字段,则会抛出异常。默认值为True。
给字段指定一个默认值。需要注意,如果字段设置了default,则隐式地表示该字段已包含required=False,如果同时指定default和required,则会抛出异常。
allow_null=True表示在序列化时允许None作为有效值。需要注意,如果没有显式使用default参数,则当指定allow_null=True时,在序列化过程中将会默认default=None,但并不会在反序列化时也默认。
一个应用于传入字段的验证函数列表,如果验证失败,会引发验证错误,否则直接是返回,用于验证字段,如:
username ``=` `serializers.CharField(max_length``=``16``, required``=``True``, label``=``'用户名'``,`` ``validators``=``[validators.UniqueValidator(queryset``=``User.objects.``all``(),message``=``'用户已经存在'``)])
验证时错误码和错误信息的一个dict,可以指定一些验证字段时的错误信息,如:
mobile``=` `serializers.CharField(max_length``=``4``, required``=``True``, write_only``=``True``, min_length``=``4``,`` ``label``=``'电话'``, error_messages``=``{`` ``'blank'``: ``'请输入验证码'``,`` ``'required'``: ``'该字段必填项'``,`` ``'max_length'``: ``'验证码格式错误'``,`` ``'min_length'``: ``'验证码格式错误'``,`` ``})
一个键值对,用于控制字段如何渲染,最常用于对密码进行密文输入,如:
password ``=` `serializers.CharField(max_length``=``16``, min_length``=``6``, required``=``True``, label``=``'密码'``,`` ``error_messages``=``{`` ``'blank'``: ``'请输入密码'``,`` ``'required'``: ``'该字段必填'``,`` ``'max_length'``: ``'密码长度不超过16'``,`` ``'min_length'``: ``'密码长度不小于6'``,` ` ``},`` ``style``=``{``'input_type'``: ``'password'``}, write_only``=``True``)
一个简短的文本字串,用来描述该字段。
一个文本字串,可用作HTML表单字段或其他描述性元素中字段的描述。
allow_blank=True 可以为空 设置False则不能为空
source=‘user.email’(user表的email字段的值给这值) 设置字段值 类似default 通常这个值有外键关联属性可以用source设置
验证该字段跟 单独的validate很像
UniqueValidator 单独唯一
validators=[UniqueValidator(queryset=UserProfile.objects.all())
UniqueTogetherValidator: 多字段联合唯一,这个时候就不能单独作用于某个字段,我们在Meta中设置。
validators = [UniqueTogetherValidator(queryset=UserFav.objects.all(),fields=(‘user’, ‘course’),message=‘已经收藏’)]
错误消息提示
error_messages={
"min_value": "商品数量不能小于一",
"required": "请选择购买数量"
})
ModelSerializers继承于Serializer,相比其父类,ModelSerializer自动实现了以下三个步骤:
使用ModelSerializer方式如下:
class UserSerializer(serializers.ModelSerializer):
# 1.独立校验器:重新设定字段, 替换掉模型中的设定, 重新设定地址的长度为5
# address_validate是自定义的数据校验函数
address = serializers.CharField(max_length=255, min_length=5, validators=
[address_validate])
# 2.单一字段验证(validate_字段名), 验证地址
def validate_address(self, data):
if data == '测试':
raise serializers.ValidationError('请填写实际地址') # 有错就抛出异常
return data # 没错就返回结果
def validate_phone(self, data):
# 不符合手机号格式
# raise serializers.ValidationError('手机号格式不正确')
model = self.root.Meta.model
num = model.objects.filter(phone=data).count()
if num > 0:
raise serializers.ValidationError('手机号已存在')
return data
# 3.所有属性验证器
def validate(self, attrs):
# attrs:{"username":"zhangsan", "phone":"18538752511", ....}
# 所有属性验证器
# self.context 中有request和view上下文
# self.context['view'].action 可以取到动作
# attrs 是需要序列化的数据
# raise serializers.ValidationError('xxx错误') # 有问题报错
return attrs # 没问题返回数据
class Meta:
model = User
# fields = ('id', ) # 临时添加字段也需要写在这里
fields = '__all__' # 所有字段
# exclude = ['id'] # 排除 id 字段
read_only_fields = ('',) # 指定字段为 read_only,
# 扩展address: extra_kwargs = {} # 局部替换某些字段的设定, 或者新增设定
extra_kwargs = {
"address": {
"min_length": 5, # 给地址增加 最小长度限制
"default": '默认测试地址', # 增加默认值
}
}
相比于Serializer,可以说是简单了不少,当然,有时根据项目要求,可能也会在ModelSerializer中显示声明字段,这些在后面总结。
该属性指定一个Model类,ModelSerializer会根据提供的Model类自动检测出需要序列化的字段。默认情况下,所有Model类中的字段将会映射到ModelSerializer类中相应的字段。
如果不希望对Model中所有的字符进行序列化,可以在fields属性中显示指定要进行序列化的字段。