序列化器
序列化器主要作用是进行一些数据校验和序列化操作。
一、 实现序列化
在子应用中新建serializers.py文件。
from rest_framework import serializers
# 定义序列化类,需继承serializers.Serializer
class ProjectSerializer(serializers.Serializer):
# 将需要校验和序列化的字段加进来,变量名和字段类型需要和models.py中一致
# 默认定义哪些字段,那么哪些字段就会序列化输出,同时这些字段也必须输入(传递)
name = serializers.CharField()
leader = serializers.CharField()
在views.py文件中使用序列化器
class ProjectView(View):
def get(self, request):
qs = Projects.objects.all()
# instance接收查询集对象;当查询集对象有多条数据需要定义many=True,只有一条数据不定义many
serializer = serializers.ProjectSerializer(instance=qs, many=True)
# data属性可以取出列表嵌套字典格式的数据,直接返回前端(返回哪些数据是由序列化类决定的)
projects_list = serializer.data
return JsonResponse(projects_list, safe=False, json_dumps_params={"ensure_ascii": False})
- 这里需要注意一下,之前的代码,更新操作其实更新的是全部字段,那么我们都知道,更新的时候其实是不校验必填项的,所以更新方法中调用serializers时,只要加上partial=True,我们就只会校验已传字段,对未传字段不予理会。
serializer = serializers.ProjectSerializer(instance=qs, data=json_dict, partial=True)
1.1 serializers参数
name = serializers.CharField(label='项目名称')
label='字段名称'
HTML页面展示API页面时,显示的字段名称
help_text='字段说明'
HTML页面展示API页面时,显示的字段帮助提示信息
max_length=10'
字段允许的最大长度
min_length=3'
字段允许的最小长度
write_only=True'
该字段必须得输入(反序列化输入),但无需输出(序列化输出),默认False
read_only=True'
该字段无需输入(反序列化输入),但必须得输出(序列化输出),该字段不会做校验。默认False
required=False'
反序列化时无须输入,默认True
default=‘默认值’
如果没有输入,反序列化时使用的默认值
allow_null=True'
该字段允许传入None(传参时是"参数名":null),默认False
allow_blank=True'
该字段允许传入空值(传参时是"参数名":""),默认False
error_messages={'字段约束参数名': '自定义的错误提示信息'}'
自定义错误提示
trim_whitespace=True'
将前后的空白字符截掉
format='%Y年%m月%d日 %H:%M:%S'
格式化输出(如果输入中文报编码错误,需要在文件开始加上locale.setlocale(locale.LC_CTYPE, 'chinese')
)
validators=[UniqueValidator(queryset=Projects.objects.all(), message='项目名不能重复'),自定义方法名])''
自定义校验器。validators有很多自带的校验规则可以使用,例如UniqueValidator。
参数约束关系
- write_only和read_only不能同时为True
- read_only和required不能同时为True
- required=True和default=‘默认值’不能同时设置
1.2 父表获取从表信息
父表的serializers.py文件
class ProjectSerializer(serializers.Serializer):
#父表模型对象获取从表的数据,默认使用“从表模型类名小写_set”;PrimaryKeyRelatedField只能输出从表的id
interfaces_set = serializers.PrimaryKeyRelatedField(label='所属接口的id', help_text='所属接口的id',
many=True, read_only=True)
#如果未指定read_only=True或者required=False,那么必须得指定queryset(指定校验时使用的查询集对象)
interfaces_set = serializers.PrimaryKeyRelatedField(label='所属接口的id', help_text='所属接口的id',
many=True, queryset=Interfaces.objects.all())
#如果不想使用“从表模型类名小写_set”作为外键,那么可在子表的model.py中定义外键字段时加上参数“related_name='interfaces'”
interfaces = serializers.PrimaryKeyRelatedField(label='所属接口的id', help_text='所属接口的id',
many=True, queryset=Interfaces.objects.all())
# StringRelatedField用于在序列化输出时,调用关联模型类中的__str__方法
# StringRelatedField默认添加了read_only=True,只用于序列化输出,而不会反序列化输入
interfaces = serializers.StringRelatedField(label='所属接口名称', help_text='所属接口名称', many=True)
# SlugRelatedField用于在序列化输出或者反序列化输入时,指定使用的关联模型类中的字段名(slug_field)
# 如果未指定read_only=True或者required=False,那么必须得指定queryset(指定校验时使用的查询集对象)
# 如果需要反序列化输入,那么slug_field必须得指定拥有唯一约束的字段名
interfaces = serializers.SlugRelatedField(label='所属接口名称', help_text='所属接口名称', many=True,
slug_field='tester', queryset=Interfaces.objects.all())
二、 实现入参的校验
校验规则为序列化器类中定义的字段规则。
views.py
# 给data传参,那么可以实现数据校验,data必须得传递Python中的基本类型(字典或者嵌套字典的列表)
serializer = serializers.ProjectSerilizer(data=python_data)
# 必须得调用is_valid方法,才会开始进行校验。如果校验通过,会返回True,否则返回False
if not serializer.is_valid():
# errors属性用于获取错误提示信息,往往为字典类型;必须得先调用is_valid方法才有errors
err = serializer.errors
return JsonResponse(err, json_dumps_params={"ensure_ascii": False}, status=400)
# serializer.validated_data可以获取校验通过之后的数据;validated_data属性,必须调用is_valid()方法后,才能获取
obj = Projects(**serializer.validated_data)
is_valid(raise_exception=True)
校验不通过会自动抛出异常- 必须先调用
is_valid()
才可以调用validated_data
、errors
及data
属性。
2.1 自定义校验器
- 自定义校验器需要在字段中加上validators参数
- validators必须得指定为序列类型(往往为列表),在列表中可以添加多个校验器
- UniqueValidator校验器进行唯一约束的校验,必须得指定queryset参数,使用message指定具体报错信息
2.1.1 校验器类外定义的校验器
- 自定义校验函数,直接将函数名放置到validators列表中
# 校验项目名称中是否包含‘项目’的方法
def is_contain_keyword(value):
# value为前端传递的项目名称
if '项目' not in value:
# 如果校验失败,必须得返回ValidationError异常对象;参数可以指定具体报错信息
raise serializers.ValidationError('项目名称中必须得包含“项目”')
class ProjectSerilizer(serializers.Serializer):
name = serializers.CharField(validators=[
UniqueValidator(queryset=Projects.objects.all(), message='项目名不能重复'),
is_contain_keyword
])
def validate_name(self, value):
if not value.endswith('项目'):
raise serializers.ValidationError('项目名称必须得以“项目”结尾')
return value
2.1.2 校验器类里定义的校验器
校验器类里定义的校验器是最后执行的,如果前面有校验不通过的,不会执行校验器类里定义的校验器。
单字段校验
class ProjectSerilizer(serializers.Serializer):
# 方法名必须为“validate_需校验的字段名”
def validate_name(self, value):
# value为前端传递的name的值
if not value.endswith('项目'):
# 如果校验不通过,必须得返回ValidationError异常对象
raise serializers.ValidationError('项目名称必须得以“项目”结尾')
# 如果校验通过,那么一般需要将校验之后的值返回
return value
多字段联合校验
单字段校验通过后才会执行多字段联合校验
class ProjectSerilizer(serializers.Serializer):
# 方法名固定为validate,接收的参数为前端传递的所有参数(dict)
def validate(self, attrs):
name = attrs.get('name', '')
leader = attrs.get('leader', '')
# 如果校验不通过,必须得返回ValidationError异常对象
if len(name + leader) > 10:
raise serializers.ValidationError('项目名与项目负责人名称总长度不超过10个字符')
# 如果校验通过,那么一般需要将校验之后的数据返回
return attrs
to_internal_value
序列化器类中的to_internal_value是在序列化器类进行校验时,首先调用的方法。
class ProjectSerilizer(serializers.Serializer):
# 方法名固定为to_internal_value,接收的参数为经过is_valid验证的数据(dict)
def to_internal_value(self, data):
some_data = super().to_internal_value(data)
some_data['leader'] = some_data['leader'].upper()
return some_data
to_representation
可以自定义返回字段某个值的内容或者新增字段返回
class ProjectSerilizer(serializers.Serializer):
def to_representation(self, instance):
instance["age"] = instance.name.age
instance= super(xxSerializer, self).to_representation(instance)
校验顺序:
调用父类的to_internal_value–>校验字段类型 --> 通用的约束参数(min_length、max_length) --> 依次校验validators中指定的校验规则-> 进入到序列化器类中–>调用单字段的校验方法 --> 进入到序列化器类中调用多字段的联合校验方法(validate方法)
三、在序列化器中操作数据库
3.1 create
在serializers.py文件中添加create方法,当调用serializers.save()时,会自动执行create方法。
class ProjectSerilizer(serializers.Serializer):
# validated_data往往为校验通过之后的数据(字典类型)
def create(self, validated_data: dict):
# 在序列化器对象调用save方法时,可以传递关键字参数,这些关键字参数会被validated_data接收,注意存入数据库前要将增加的参数删掉,不然会报错
obj = Projects.objects.create(**validated_data)
# 必须得将创建的模型类对象返回
return obj
修改views.py文件中的post方法。
class ProjectViews(View):
try:
python_data = json.loads(request.body.decode('utf-8'))
except Exception:
return JsonResponse(err_msg, json_dumps_params={"ensure_ascii": False}, status=400)
serializer = serializers.ProjectSerilizer(data=python_data)
if not serializer.is_valid():
err = serializer.errors
return JsonResponse(err, json_dumps_params={"ensure_ascii": False}, status=400)
# 序列化器对象调用save方法时,会调用序列化器类中的create方法,进行数据创建操作
serializer.save()
# obj = Projects(**serializer.validated_data)
# obj.save()
# serializer = serializers.ProjectSerilizer(instance=obj)
return JsonResponse(serializer.data, json_dumps_params={"ensure_ascii": False})
3.2 update
在serializers.py文件中添加update方法,当调用serializers.save()时,会自动执行update方法。
- 注意:create方法和update方法都是调用serializers.save()时自动执行,区别是save传参带既有instance又有validated_data时,执行update方法,只传validated_data时,执行create方法。
class ProjectSerilizer(serializers.Serializer):
# validated_data往往为校验通过之后的数据(字典类型),instance为待更新的模型类对象
def update(self, instance, validated_data):
# 在序列化器对象调用save方法时,可以传递关键字参数,这些关键字参数会被validated_data接收
instance.name = validated_data.get('name') or instance.name
instance.leader = validated_data.get('leader') or instance.leader
instance.desc = validated_data.get('desc') or instance.desc
instance.is_execute = validated_data.get('is_execute') or instance.is_execute
instance.save()
# 必须得将更新的模型类对象返回
return instance
修改views.py文件中的put方法。
class ProjectDetailView(View):
def put(self, request, pk):
try:
python_data = json.loads(request.body.decode('utf-8'))
except Exception:
return JsonResponse(err_msg, json_dumps_params={"ensure_ascii": False}, status=400)
obj = Projects.objects.get(id=pk)
serializer = serializers.ProjectSerilizer(instance=obj, data=python_data)
if not serializer.is_valid():
err = serializer.errors
return JsonResponse(err, json_dumps_params={"ensure_ascii": False}, status=400)
# 5、数据更新
# obj.name = serializer.validated_data.get('name') or obj.name
# obj.leader = serializer.validated_data.get('leader') or obj.leader
# obj.desc = serializer.validated_data.get('desc') or obj.desc
# obj.is_execute = serializer.validated_data.get('is_execute') or obj.is_execute
# obj.save()
# 序列化器对象调用save方法时,会调用序列化器类中的update方法,进行数据更新操作
serializer.save()
# serializer = serializers.ProjectSerilizer(instance=obj)
return JsonResponse(serializer.data, json_dumps_params={"ensure_ascii": False}, status=201)