一、进一步封装优化序列化器
- 注意:更高一级的封装,代表着更少的代码,也代表着更低的可定制型
- 要讲诉的方法,类似
Django
原生的ModelForm
对model
的引用
二、ModelSerializer
类
-
ModelSerializer
类能够让我们自动你创建一个具有对应模型类中,相对应字段的Serializer
类 -
ModelSerializer
类直接继承了Serializer
类,不同的是:
1.它根据model模型的定义,自动生成默认字段。
2.它自动生成序列化器的验证器,比如unique_together
验证器。
3.它实现了简单的.create()
方法和.update()
方法。 - 声明一个
ModelSerializer
类,(用之前写好的序列化器示例,注释之前的类属性字段,修改成ModelSerializer
类)
class UserSerializer(serializers.ModelSerializer):
class Meta:
# 需要序列化的model类
model = User
# 序列化所有的字段
# fields = '__all__'
# 序列化指定字段
# fields = ('name', 'password', 'email', 'sex')
# 排除哪些字段不进行序列化
exclude = ('email',)
注意:由于对应了model
类的字段,会存在必填字段,所以fileds=__all__
和exclude
慎重使用
-
进入shell查看
ModelSerializer
类自动创建了哪些字段和验证器(fileds=__all__
的)
-
测试是否能添加成功:
2.1、明确指定字段
当觉得全自动的字段不满足需求时,可以通过在ModelSerializer
类上显式声明字段,从而增加额外的字段或者重写默认的字段,就和在Serializer
类一样的。
比如:
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)
class Meta:
model = User
fields = '__all__'
2.2、指定只读字段
当我们希望批量将某些字段指定为只读,而不是显式的逐一为每个字段添加read_only=True
属性,这种情况就可以使用Meta
的read_only_fields
选项。
该选项的值是字段名称所组成的列表或元组,并像下面这样声明:
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)
class Meta:
model = User
fields = '__all__'
read_only_fields = ('sex', 'password')
注意: 有一种特殊情况,其中一个只读字段是模型级别unique_together
约束的一部分。在这种情况下,序列化器需要该字段的值才能验证约束,但也是不能由用户编辑的。
处理此问题的正确方法是在序列化器上显式指定该字段,同时提供read_only=True和default=…
关键字参数。
这种情况的一个例子就是对于一个和其他标识符unique_together
的当前认证的User
是只读的。 在这种情况下可以像下面这样声明user
字段:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
-
PrimaryKeyRelatedField
处理反向关联关系/反向序列化
比如说interfaces是projects的从表。此时的设计是:在创建interface时,前端会传递一个project_id
,我们实际在创建interface时,是不会使用project_id
,project_id
在interfaces.model
和projects.model
是一个反向关联关系。所以我们此时需要为它添加一个显示字段。
interfaces/serialzers.py
from rest_framework import serializers
from projects.models import Projects
from interfaces.models import Interfaces
class InterfaceModelSerializer(serializers.ModelSerializer):
# 从表指定输出主表外键输出的值
project = serializers.StringRelatedField(label='所属项目', read_only=True)
# 新增model不存在的字段,前端传递的是project_id,并且和project表是一个反向关联关系,所以需要添加一个显示字段
project_id = serializers.PrimaryKeyRelatedField(queryset=Projects.objects.all(), write_only=True,
label='所属项目id', help_text='所属项目id')
class Meta:
model = Interfaces
fields = ('id', 'name', 'tester', 'create_time', 'desc', 'project', 'project_id')
extra_kwargs = {
'create_time': {
'read_only': True
}
}
def create(self, validated_data):
"""
前端传的是project_id,而对应的字段应该是project,所以需要处理下这里
:param validated_data:
:return:
"""
project_id = validated_data.pop('project_id')
validated_data['project'] = project_id
interface_obj = super().create(validated_data)
return interface_obj
2.3、添加关键字参数
可以通过使用extra_kwargs
选项快捷地在字段上指定任意附加的关键字参数。这个选项是一个将具体字段名称当作键值的字典。
- 用法:在给字段添加
ModelSerializer
无法自动添加的额外条件时使用 - 注意:
extra_kwargs
的值是一个字段,里面的key需要和校验参数一致,否则出错(可看源码)
例如:
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
# model的任意字段
"name": {
"write_only": True, # 字段名别写错
"error_messages": { # 字段名别写错
"max_length": "用户名最多不能超过50个字符"
}
}
}
2.4、添加序列化器自定义的校验
- 直接复制粘贴过来,但是要注意,必须和
class Meta
平级
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
# model的任意字段
"name": {
"write_only": True, # 字段名别写错
"error_messages": { # 字段名别写错
"max_length": "用户名最多不能超过50个字符"
}
}
}
# 自定义字段级别的验证
def validate_name(self, value):
"""
用户名需要以“用户”开头
:return:
"""
if not str(value).startswith('用户'):
# 抛出erializers.ValidationError异常
raise serializers.ValidationError(detail='用户名需要以用户两个字开头')
# 返回一个验证过的数据
else:
return attrs
# 自定义多个字段的组合验证规则
def validate(self, attrs):
"""
password和email必需含有“lzl”这三个字母
:return:
"""
if "lzl" not in attrs['password'] or "lzl" not in attrs['email']:
raise serializers.ValidationError(detail='password和email必需含有“lzl”这三个字母')
else:
return attrs
2.5、views.py
的修改
-
ModelSerializer
类因为实现了简单的.create()
方法和.update()
方法。所以之前的views.py
中的代码只需要把之前的Serializer
类改成调用继承了ModelSerializer
的类即可
2.6、指定外键序列化输出的值(从表指定主表外键)
主表:projcet
从表:interface
在interface副表中,外键是projcet
当使用ModelSerializer
进行序列化时,默认会对project外键进行处理,默认生成的是PrimaryKeyRelatedField序列化器字段,序列化输出的是该interface对应的project表的id。
如果需要修改,那么需要显示处理:
from rest_framework import serializers
from interfaces.models import Interfaces
from projects.serializer import ProjectModelSerializer
class InterfaceModelSerializer(serializers.ModelSerializer):
# 指定外键序列化输出内容(project是interface的外键字段)
# 1、StringRelatedField:此字段会被序列化为关联对象字符串表达形式,也就是__str__方法的内容
project = serializers.StringRelatedField(label='所属项目')
# 2、SlugRelatedField:指定序列化返回的字段,比如下面序列化的结果是关联project表的leader字段的值
project = serializers.SlugRelatedField(label='所属项目', slug_field='leader')
# 3、 指定返回关联的project序列化器(需要指定read_only,不然前端就需要输入一个project序列化器)
project = ProjectModelSerializer((label='所属项目', read_only=True)
class Meta:
model = Interfaces
fields = '__all__'
2.6、指定外键序列化输出的值(主表指定从表)
主表中不会默认生成从表的关联字段,需要手动指定,并且字段名是从表名_set
。其它方法和和在从表指定主表的一样。
class ProjectModelSerializer(serializers.ModelSerializer):
#注意字段名,并且由于是从表,多的一方,要指定many=True
interfaces_set = serializers.StringRelatedField(label='项目接口', many=True)
class Meta:
model = Interfaces
fields = '__all__'