欢迎关注我的公众号「测试游记」
序列化器
序列化器中定义的类属性字段,往往与模型类字段一一对应
label选项相当于
verbose_name
;定义的序列化器字段,默认既可以进行序列化输出,也可以进行反序列化输入
通用参数
read_only=True
指定该字段只能进行序列化输出write_only=True
指定该字段只进行反序列化输入,但不进行序列化输出required
该字段在反序列化时必须传入,默认为Truedefault
反序列化时使用的默认值allow_null
该字段是否允许传入None,默认Falsevalidators
该字段使用的校验器error_messages
包含错误key与错误信息的字典(下面有例子)label
用于HTML展示API页面时,显示的字段名称
选项参数
max_length
最大长度min_length
最小长度allow_blank
是否允许为空trim_whitespace
是否截断空白字符max_value
最小值min_value
最大值
校验
调用序列化器对象的
is_valid
方法,才开始校验前端参数如果校验成功,则返回
True
,校验失败返回False
raise_exception=True
,校验失败后会抛出异常当调用
is_valid
方法之后,才可以调用errors
属性「校验的错误提示(字典)」
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return JsonResponse(serializer.errors)
在序列化器中增加 validators
from rest_framework.validators import UniqueValidator
from projects.models import Projects
name = serializers.CharField(
label='项目名称',
max_length=200,
help_text='项目名称',
validators=[
UniqueValidator(
queryset=Projects.objects.all(),
message='项目名不能重复'
)
]
)
编写一份创建项目的json
发送一个创建请求
$ http POST :8000/project/ < projects.json
zhongxindeMacBook-Pro:apitest zhongxin$ http POST :8000/project/ < projects.json
HTTP/1.1 200 OK
Content-Length: 56
Content-Type: application/json
Date: Wed, 16 Oct 2019 12:34:16 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-Frame-Options: SAMEORIGIN
{
"name": [
"项目名不能重复"
]
}
自定义校验
自己编写一个校验器
需求:项目名称中必须包含 项目
关键字
def is_unique_project_name(name):
"""
项目名称中需要包含「项目」关键字
:param name:前端传递给我的项目名称
:return:
"""
if '项目' not in name:
raise serializers.ValidationError(detail='项目名称中必须包含「项目」')
name = serializers.CharField(
label='项目名称',
max_length=200,
help_text='项目名称',
validators=[
UniqueValidator(
queryset=Projects.objects.all(),
message='项目名不能重复'
), is_unique_project_name
]
)
单字段校验
在序列化器内部增加 defvalidate_name(self,value):
# 单字段的校验
def validate_name(self, value):
if value.endswith('项目'):
raise serializers.ValidationError('项目名称必须以「项目」结尾')
# projects.json
{
"name": "测试游记1",
"leader": "zhongxin",
"tester": "zhongxin",
"programer": "zhong3",
"publish_app": "公众号",
"desc": "无"
}
修改 projects.json
# projects.json
{
"name": "测试游记项目1",
"leader": "zhongxin",
"tester": "zhongxin",
"programer": "zhong3",
"publish_app": "公众号",
"desc": "无"
}
多字段校验
def validate(self, attrs):
pass
这里 name
为 None
是因为上面单字段校验没有返回value
修改后再次测试
def validate_name(self, value):
if not value.endswith('项目'):
raise serializers.ValidationError('项目名称必须以「项目」结尾')
else:
return value
def validate(self, attrs):
"""
多字段联合校验
需求:tester和leader中有「icon」
:param attrs:
:return:
"""
if 'icon' not in attrs['tester'] and 'icon' not in attrs['leader']:
raise serializers.ValidationError('「icon」必须是项目负责人或者在项目的测试人员')
else:
return attrs
修改 projects.json
# projects.json
{
"name": "测试游记项目",
"leader": "icon",
"tester": "zhongxin",
"programer": "zhong3",
"publish_app": "公众号",
"desc": "无"
}
校验器的顺序
字段定义时的限制,包含
validators
列表条目从左到右进行校验单字段「
validate_字段名
」的校验多字段联合校验「
validate
方法」
优化视图内代码
如果在创建序列化器对象时候,只给data传参,那么调用save()方法实际调用的就是序列化器对象的
create()
方法在创建序列化器对象时,同时给instance和data传参,那么调用save()方法实际调用的就是序列化器对象的
update()
方法
序列化器类 ProjectSerializer
中增加 create
和 update
def create(self, validated_data):
return Projects.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data['name']
instance.leader = validated_data['leader']
instance.tester = validated_data['tester']
instance.programer = validated_data['programer']
instance.publish_app = validated_data['publish_app']
instance.desc = validated_data['desc']
instance.save()
return instance
修改post请求
从
def post(self, request):
"""
新建项目
"""
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
serializer = ProjectSerializer(data=python_data)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return JsonResponse(serializer.errors)
project = Projects.objects.create(**serializer.validated_data)
serializer = ProjectSerializer(instance=project)
return JsonResponse(serializer.data, status=201)
改为
def post(self, request):
"""
新建项目
"""
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
serializer = ProjectSerializer(data=python_data)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return JsonResponse(serializer.errors)
serializer.save()
return JsonResponse(serializer.data, status=201)
修改put请求
从
def put(self, request, pk):
project = self.get_object(pk)
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
serializer = ProjectSerializer(data=python_data)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return JsonResponse(serializer.errors)
project.name = serializer.validated_data['name']
project.leader = serializer.validated_data['leader']
project.tester = serializer.validated_data['tester']
project.programer = serializer.validated_data['programer']
project.publish_app = serializer.validated_data['publish_app']
project.desc = serializer.validated_data['desc']
project.save()
serializer = ProjectSerializer(instance=project)
return JsonResponse(serializer.data, status=201)
改为
def put(self, request, pk):
project = self.get_object(pk)
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
serializer = ProjectSerializer(instance=project, data=python_data)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
return JsonResponse(serializer.errors)
serializer.save()
return JsonResponse(serializer.data, status=201)
优化序列化器
from rest_framework import serializers
class ProjectModelSerializer(serializers.ModelSerializer):
class Meta:
# 指定参考哪一个模型类来创建
model = Projects
# 指定为模型类的哪些字段,来生成序列化器
fields = '__all__'
In[2]:from projects import serializer
In[3]:serializer.ProjectModelSerializer()
Out[3]:
ProjectModelSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(help_text='项目名称', label='项目名称', max_length=200, validators=[<UniqueValidator(queryset=Projects.objects.all())>])
leader = CharField(help_text='负责人', label='负责人', max_length=50)
tester = CharField(help_text='测试人员', label='测试人员', max_length=50)
programer = CharField(help_text='开发人员', label='开发人员', max_length=50)
publish_app = CharField(help_text='发布应用', label='发布应用', max_length=50)
desc = CharField(allow_blank=True, allow_null=True, help_text='简要描述', label='简要描述', required=False, style={'base_template': 'textarea.html'})
fields = ('id', 'name', 'leader', 'tester', 'programer', 'publish_app')
exclude = ('publish_app')
read_only_fields = ('leader','tester')
fields
:指定显示哪些exclude
:指定排除哪些read_only_fields
:指定read_only=True
的字段
如果需要修改 name
的校验,自定义一个 name
字段
class ProjectModelSerializer(serializers.ModelSerializer):
name = serializers.CharField(
label='项目名称',
max_length=200,
help_text='项目名称',
validators=[
UniqueValidator(
queryset=Projects.objects.all(),
message='项目名不能重复'
), is_unique_project_name
],
error_messages={'max_length': '长度不能超过200个字节'}
)
class Meta:
model = Projects
fields = '__all__'
read_only_fields = ('leader', 'tester')
也可以增加 extra_kwargs
增加其他内容
class Meta:
# 指定参考哪一个模型类来创建
model = Projects
# 指定为模型类的哪些字段,来生成序列化器
fields = '__all__'
extra_kwargs = {
'leader': {
'write_only': True,
'error_messages': {'max_length': '长度不能超过50个字节'}
}
}
测试一下:
Out[3]:
ProjectModelSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(error_messages={'max_length': '长度不能超过200个字节'}, help_text='项目名称', label='项目名称', max_length=200, validators=[<UniqueValidator(queryset=<QuerySet [<Projects: 测试游记>, <Projects: 测试游记1>, <Projects: 「测试游记」-创建>, <Projects: 1015项目>, <Projects: 测试游记项目>]>)>, <function is_unique_project_name>])
leader = CharField(error_messages={'max_length': '长度不能超过50个字节'}, help_text='负责人', label='负责人', max_length=50, write_only=True)
tester = CharField(help_text='测试人员', label='测试人员', max_length=50)
programer = CharField(help_text='开发人员', label='开发人员', max_length=50)
publish_app = CharField(help_text='发布应用', label='发布应用', max_length=50)
desc = CharField(allow_blank=True, allow_null=True, help_text='简要描述', label='简要描述', required=False, style={'base_template': 'textarea.html'})