一、序列化器作用
1、数据格式转换:
序列化: 对象 -> 字典
反序列化: 字典 -> 对象(OrderedDict)
2、校验参数合法性;
3、保存和修改数据;
二、定义序列化器
通过继承rest_framework.serializers.Serializer来定义序列化器
1、基本定义
class Department(models.Model):
"""部门模型类"""
name = models.CharField(max_length=20, verbose_name='部门名称')
create_date = models.DateField(verbose_name='成立时间')
is_delete = models.BooleanField(default=False, verbose_name='是否删除')
def __str__(self):
return self.name
class Meta(object):
db_table = 'department'
class Employee(models.Model):
"""员工模型类"""
choices_gender = (
(0, '男'),
(1, '女'),
)
name = models.CharField(verbose_name='姓名', max_length=20)
age = models.IntegerField()
gender = models.IntegerField(verbose_name='年龄', default=0, choices=choices_gender)
salary = models.DecimalField(verbose_name='工资', max_digits=8, decimal_places=2)
comment = models.CharField(verbose_name='备注', max_length=300, null=True, blank=True)
hire_date = models.DateField(verbose_name='入职时间', auto_now_add=True)
# 关联属性
department = models.ForeignKey('Department', verbose_name='所属部门')
def __str__(self):
return self.name
class Meta(object):
db_table = 'employee'
2.、常用字段类型:
字段 | 字段构造方式 |
---|---|
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') |
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) |
ChoiceField | ChoiceField(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) |
三、使用序列化器
序列化: 模型对象 -> 字典
1、序列化器的创建
Serializer(instance=None, data=empty, **kwarg)
# instance: 用于序列化时,传入要序列化的模型类对象。
# data: 用于反序列化时,传入字典数据
2、序列化操作
data属性: 获取序列化后得到的字典
from users.models import *
from users.serializers import *
dep = Department.objects.get(id=1)
serializer = DepartmentSerializer(dep)
serializer.data
# {'create_date': '2009-01-01', 'name': '研发部',
# 'is_delete': False, 'id': 1}
3、序列化操作: many=True参数
如果要序列化的是包含多条数据的QuerySet,则需要指定many=True,否则报错:
serializer = DepartmentSerializer(query_set, many=True)
serializer.data
# [OrderedDict([('id', 1), ('name', '研发部'), ('create_date', '2009-01-01'), ('is_delete', False)]),
# OrderedDict([('id', 2), ('name', '人事部'), ('create_date', '2009-03-01'), ('is_delete', False)])]
四、序列化关联对象
关联对象序列化时,需要指定该如何序列化关联对象
第一种情况: 要序列化的关联对象只有一个,例如:员工对象
最常用的,有如下序列化方式
1、 PrimaryKeyRelatedField
此字段将被序列化为关联对象的主键
必须包含read_only=True或者queryset参数:
包含read_only=True参数时,该字段反序列化时不能使用
包含queryset参数时,将在反序列化,会用作参数合法性校验
department = serializers.PrimaryKeyRelatedField(label='所属部门', read_only=True)
或
department = serializers.PrimaryKeyRelatedField(label='所属部门', queryset=Department.objects.all())
序列化结果:
from users.serializers import *
from users.models import *
employee = Employee.objects.get(id=1)
serializer = EmployeeSerializer(employee)
serializer.data
# {'salary': '12000.00', 'comment': None, 'avatar': None,
# 'department': 1, 'gender': 0, 'age': 28, 'hire_date': '2011-01-01', 'id': 1, 'name': '赵小一'}
2、使用关联对象的序列化器
department = DepartmentSerializer()
序列化结果:
from users.serializers import *
from users.models import *
employee = Employee.objects.get(id=1)
serializer = EmployeeSerializer(employee)
serializer.data
# {'avatar': None, 'comment': None, 'hire_date': '2011-01-01',
# 'salary': '12000.00', 'id': 1, 'name': '赵小一', 'gender': 0,
# 'department': OrderedDict([('id', 1), ('name', '研发部'),
# ('create_date', '2009-01-01'), ('is_delete', False)]), 'age': 28}
第二种情况: 要序列化的关联对象包含多个,例如:想序列化 部门对象时,把部门 关联的员工对象也进行序列化。
配置关联字段类型仍是使用上述介绍的PrimaryKeyRelatedField等方式,只是在声明关联字段时,多补充一个many=True参数
class DepartmentSerializer(serializers.Serializer):
"""部门数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
name = serializers.CharField(label='部门名称', max_length=20)
create_date = serializers.DateField(label='成立时间')
is_delete = serializers.BooleanField(label='是否删除', required=False)
# 此处仅拿PrimaryKeyRelatedField类型来举例,其他相同
employee_set = serializers.PrimaryKeyRelatedField(label='员工', read_only=True, many=True)
序列化结果:
from users.models import *
from users.serializers import *
dep = Department.objects.get(id=1)
serializer = DepartmentSerializer(dep)
serializer.data
# {'id': 1, 'create_date': '2009-01-01', 'is_delete': False,
# 'employee_set': [1, 2, 3, 4, 14], 'name': '研发部'}
五、反序列化
1、反序列化基本使用
反序列化: 字典 -> 对象(OrderedDict)
序列化器的创建: 通过data传入字典数据
Serializer(instance=None, data=empty, **kwarg)
通过is_valid方法校验参数合法性
is_valid()方法:
校验参数是否合法:会根据定义序列化器时,指定的序列化类型和选项参数,进行参数校验,校验通过返回True,否则返回False;
传递参数:is_valid(raise_exception=True);
验证失败时会抛出异常serializers.ValidationError;
REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应;
errors属性: 获取校验出错信息,字典类型,包含了字段和字段的错误;
validated_data属性: 校验通过得到的对象,类型为OrderedDict;
案例:
案例一:验证不通过
my_dict = {'create_date':'2018'}
serializer = DepartmentSerializer(data=my_dict)
serializer.is_valid() # 验证不通过
# False
serializer.errors
# {'create_date': [ErrorDetail(string='Date has wrong format.
# Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')],
# 'name': [ErrorDetail(string='This field is required.', code='required')]}
案例二:验证通过
my_dict = {'name':'研发部33', 'create_date':'2018-1-1'}
serializer = DepartmentSerializer(data=my_dict)
serializer.is_valid() # 验证通过
# True
serializer.validated_data
# OrderedDict([('name', '研发部33'),
# ('create_date', datetime.date(2018, 1, 1))])
六、参数校验的几种方式
1、validate_
class DepartmentSerializer(serializers.Serializer):
"""部门数据序列化器"""
...
def validate_name(self, value):
# 校验部门名称
if not re.match('^[A-Za-z\u4e00-\u9fa5]+$', value):
raise ValidationError('部门名称只能为中文或英语字母')
return value
2、validate方法:对多个字段进行比较校验,例:
# 模型: users/models.py
class User(models.Model):
password = models.CharField(max_length=30)
password2 = models.CharField(max_length=30)
# 序列化器: users/serializer.py
class UserSerializer(serializers.Serializer):
password = serializers.CharField(max_length=30)
password2 = serializers.CharField(max_length=30)
def validate(self, attrs):
# 校验两次输入的密码是否正确
password = attrs['password']
password2 = attrs['password2']
if password != password2:
raise serializers.ValidationError('两个输入的密码不一样')
return attrs
3、validators字段选项:在序列化器字段中添加validators选项参数进行校验,例:
使用 UniqueValidator(字段唯一) 校验字段不能重复
class DepartmentSerializer(serializers.Serializer):
"""部门数据序列化器"""
...
name = serializers.CharField(label='部门名称', max_length=20,
validators=[UniqueValidator(queryset=Department.objects.all())])
七、保存或修改数据
1、Serializer类的三个方法
save()方法: 新增或修改
create(self, validated_data)方法: 新增数据
update(self, instance, validated_data)方法: 修改数据
2、Serializer类的save()方法: 新增或修改一条数据
DepartmentSerializer(instance=None, data=my_dict)
创建Serializer对象时,如果没有传递instance实例
调用Serializer对象的save()方法时会执行create()新增数据
DepartmentSerializer(instance=department, data=my_dict)
创建Serializer对象时,传递了instance实例
调用Serializer对象的save()方法时会执行update()修改数据:
department = Department.objects.get(id=1)
my_dict = {'name': '研发部xx', 'create_date': '2018-1-1'}
s = DepartmentSerializer(instance=department, data=my_dict)
s.save() # 修改数据
3、required=True参数
(1)当修改数据时,序列化器默认要求传递所有required=True的字段,否则is_valid验证不通过
(2)可以通过设置partial=True允许只修改部分字段,如下:
s = DepartmentSerializer(comment, data={'create_date': '2017-1-1'}, partial=True)
4、重写 Serializer类的create()和update()方法
class DepartmentSerializer(serializers.Serializer):
"""部门序列化器"""
...
def create(self, validated_data):
"""保存部门"""
return Department.objects.create(**validated_data)
def update(self, instance, validated_data):
"""修改部门:instance为要修改的部门对象,
validated_data为用户发请求提交过来的数据,已经通过校验
"""
instance.name = validated_data.get('name', instance.name)
instance.create_date = validated_data.get('create_date', instance.create_date)
instance.save() # 修改数据库数据
return instance
八、模型序列化器
DRF提供了模型类序列化器: ModelSerializer
作用: 简化对应django模型类的序列化器的定义
ModelSerializer与常规的Serializer相同,但提供了:
基于模型类自动生成一系列字段;
基于模型类自动为Serializer生成validators;
包含默认的create()和update()的实现;
1、 定义
class DepartmentSerializer(serializers.ModelSerializer):
"""部门序列化器"""
class Meta:
model = Department # 关联的模型类对象
fields = '__all__' # 表示包含模型类中所有字段
在python console 交互环境中,查看生成的序列化器
>>> s = DepartmentSerializer()
>>> s
DepartmentSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(label='部门名称', max_length=20)
create_date = DateField(label='成立时间')
is_delete = BooleanField(label='是否删除', required=False)
2、属性说明
class DepartmentSerializer(serializers.ModelSerializer):
employee_set = EmployeeSerializer() # 新增模型类不存在字段
class Meta:
model = Department
# fields = '__all__'
exclude = ('is_delete',)
read_only_fields = ('id',) # 部门id,成立时间
extra_kwargs = {
'name': {'required': True, 'min_length': 2, 'max_length': 20}
}
结果如下:
DepartmentSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(max_length=20, min_length=2, required=True)
create_date = DateField(read_only=True)
employee_set = EmployeeSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(label='姓名', max_length=20)
age = IntegerField(label='年龄')
gender = ChoiceField(choices=((0, '男'), (1, '女')), default=0, label='性别')
salary = DecimalField(decimal_places=2, label='工资', max_digits=8)
comment = CharField(label='备注', max_length=300, required=False)
hire_date = DateField(label='入职时间', required=False)
department = PrimaryKeyRelatedField(help_text='所属部门', label='所属部门', read_only=True)