DRF ---- ModelSerializer ListSerializer
目录
模型类序列化器
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮
助我们快速创建一个Serializer类。
ModelSerializer类已经帮我们实现了 create 与 update 方法
比如我们创建一个BookInfoSerializer
# 注意点: 继承ModelSerializer 定义内部类 Meta
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = '__all__'
- model 指明参照哪个模型类
- fields 指明为模型类的哪些字段生成
1.参数
model 参数
model 指明参照哪个模型类
fields 参数
使用fields来明确字段,__all__
表名包含所有字段,也可以写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date')
extra_kwargs 参数
我们可以使用extra_kwargs参数为ModelSerializer
添加或修改原有的选项参数
-
划分系统字段为三种:
-
只读(read_only)
-
只写(write_only)
-
可读可写(不设置)
-
-
字段是否必须:
required
选填字段 默认False
extra_kwargs = {
'username': { # 系统字段不设置read_only和write_only,默认都参加
'min_length': 3,
'max_length': 10,
'error_messages': {
'min_length': '太短',
'max_length': '太长'
}
},
'gender': {
'read_only': True, # 自定义的序列化字段默认就是read_only,且不能修改,可以省略
},
'sex': { # 像sex有默认值的字段,为选填字段('required': True可以将其变为必填字段)
'write_only': True,
'required': True
}
}
exclude 参数
使用exclude可以明确排除掉哪些字段
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
# 与fields不共存,exclude排除哪些字段
exclude = ('image',)
read_only_fields 参数
指明只读字段
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
read_only_fields = ('id', 'bread', 'bcomment')
depth 参数
自动连表深度
# 外键字段默认显示的是外键值(int类型),不会自己进行深度查询
class Meta:
model = models.Book
fields = ('name', 'price', 'img', 'author_list', 'publish')
# 自动连表深度
depth = 1
2 .自定义序列化字段
第一种方式
class UserModelSerializer(serializers.ModelSerializer):
# 第一种自定义序列化字段:该字段必须在 fields 中设置
gender = serializers.SerializerMethodField()
def get_gender(self, obj):
return obj.get_sex_display()
class Meta:
model = models.User
# fields采用 插拔式 设置所有参与序列化与反序列化字段
fields = ('gender')
第二种方式
class User(models.Model):
sex = models.IntegerField(choices=SEX_CHOICES, default=0, verbose_name='性别')
# 第二种自定义序列化字段(插拔式,提倡使用)
@property
def gender(self):
return self.get_sex_display()
class Meta:
model = models.User
fields = ('gender')
3.连表深度
外键字段默认显示的是外键值(int类型),不会自己进行深度查询
方式一
自动深度查询的是关联表的所有字段,数据量太多
# 外键字段默认显示的是外键值(int类型),不会自己进行深度查询
class Meta:
model = models.Book
fields = ('name', 'price', 'img', 'author_list', 'publish')
# 自动连表深度
depth = 1
方式二
必须有子序列化类配合,不能反序列化了
# 可以单独作为Publish接口的序列化类,也可以作为Book序列化外键publish 辅助的序列化组件
class PublishModelSerializer(ModelSerializer):
class Meta:
model = models.Publish
fields = ('name', 'address')
class BookModelSerializer(ModelSerializer):
# 自定义连表深度 - 子序列化方式 - 该方式不能参与反序列化
publish = PublishModelSerializer()
class Meta:
model = models.Book
fields = ('name', 'price', 'img', 'author_list', 'publish')
# 自动连表深度
# depth = 1
方式三
名字不能与外键名同名
@property
def publish_info(self): # 单个数据
return {
'name': self.publish.name,
'address': self.publish.address,
}
@property
def author_list(self):
author_list_temp = [] # 存放所有作者格式化成数据的列表
authors = self.authors.all() # 所有作者
for author in authors: # 遍历处理所有作者
author_dic = {
'name': author.name,
}
try: # 有详情才处理详情信息
author_dic['mobile'] = author.detail.mobile
except:
author_dic['mobile'] = '无'
author_list_temp.append(author_dic) # 将处理过的数据添加到数据列表中
return author_list_temp # 返回处理后的结果
4 .自定义反序列化字段(重点!)
# 自定义反序列化字段同Serializer类,且规则只能在此声明中设置,或是在钩子中设置
# 在extra_kwargs中对其设置的无效
# 注:自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
(重点!!!)
re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)
5.钩子校验
使用方法和 serializer
一样
全局钩子
def validate(self, attrs):
if attrs.get('xxx'):
raise ValidationError({'book': '该书已存在'})
return attrs
局部钩子
def validate_name(self, value):
if 'xxx' in value:
raise ValidationError('该g书不能出版')
return value
6.四大接口(重中之重)
序列化与反序列化结合
"""
1) fields中设置所有序列化与反序列化字段
2) extra_kwargs划分只序列化或只反序列化字段
write_only:只反序列化
read_only:只序列化
自定义字段默认只序列化(read_only)
3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
"""
class V2BookModelSerializer(ModelSerializer):
class Meta:
model = models.Book
fields = ('name', 'price', 'img', 'author_list', 'publish_name', 'publish', 'authors')
extra_kwargs = {
'name': {
'required': True,
'min_length': 1,
'error_messages': {
'required': '必填项',
'min_length': '太短',
}
},
'publish': {
'write_only': True
},
'authors': {
'write_only': True
},
'img': {
'read_only': True,
},
'author_list': {
'read_only': True,
},
'publish_name': {
'read_only': True,
}
}
def validate_name(self, value):
# 书名不能包含 g 字符
if 'g' in value.lower():
raise ValidationError('该g书不能出版')
return value
def validate(self, attrs):
publish = attrs.get('publish')
name = attrs.get('name')
if models.Book.objects.filter(name=name, publish=publish):
raise ValidationError({'book': '该书已存在'})
return attrs
单查群查
# 单查群查
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
book_ser = serializers.BookModelSerializer(book_obj)
else:
book_query = models.Book.objects.filter(is_delete=False).all()
book_ser = serializers.BookModelSerializer(book_query, many=True)
return APIResponse(results=book_ser.data)
单删群删
def delete(self, request, *args, **kwargs):
"""
单删:接口:/books/(pk)/ 数据:空
群删:接口:/books/ 数据:[pk1, ..., pkn]
逻辑:修改is_delete字段,修改成功代表删除成功,修改失败代表删除失败
"""
pk = kwargs.get('pk')
if pk:
pks = [pk] # 将单删格式化成群删一条
else:
pks = request.data # 群删
try: # 数据如果有误,数据库执行会出错
rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
except:
return APIResponse(1, '数据有误')
if rows:
return APIResponse(0, '删除成功')
return APIResponse(1, '删除失败')
单增群增
def post(self, request, *args, **kwargs):
"""
单增:接口:/books/ 数据:{...}
群增:接口:/books/ 数据:[{...}, ..., {...}]
逻辑:将数据给系列化类处理,数据的类型关系到 many 属性是否为True
"""
if isinstance(request.data, dict):
many = False
elif isinstance(request.data, list):
many = True
else:
return Response(data={'detail': '数据有误'}, status=400)
book_ser = serializers.BookModelSerializer(data=request.data, many=many)
book_ser.is_valid(raise_exception=True)
book_obj_or_list = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_obj_or_list, many=many).data)
整体 单改群改
def put(self, request, *args, **kwargs):
"""
单改:接口:/books/(pk)/ 数据:{...}
群增:接口:/books/ 数据:[{pk, ...}, ..., {pk, ...}]
逻辑:将数据给系列化类处理,数据的类型关系到 many 属性是否为True
"""
pk = kwargs.get('pk')
if pk: # 单改
try:
# 与增的区别在于,需要明确被修改的对象,交给序列化类
book_instance = models.Book.objects.get(is_delete=False, pk=pk)
except:
return Response({'detail': 'pk error'}, status=400)
book_ser = serializers.BookModelSerializer(instance=book_instance, data=request.data)
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
else: # 群改
# 分析(重点):
# 1)数据是列表套字典,每个字典必须带pk,就是指定要修改的对象,如果有一条没带pk,整个数据有误
# 2)如果pk对应的对象已被删除,或是对应的对象不存在,可以认为整个数据有误(建议),可以认为将这些错误数据抛出即可
request_data = request.data
try:
pks = []
for dic in request_data:
pk = dic.pop('pk') # 解决分析1,没有pk pop方法就会抛异常
pks.append(pk)
book_query = models.Book.objects.filter(is_delete=False, pk__in=pks).all()
if len(pks) != len(book_query):
raise Exception('pk对应的数据不存在')
except Exception as e:
return Response({'detail': '%s' % e}, status=400)
book_ser = serializers.BookModelSerializer(instance=book_query, data=request_data, many=True)
book_ser.is_valid(raise_exception=True)
book_list = book_ser.save()
return APIResponse(results=serializers.BookModelSerializer(book_list, many=True).data)
局部单改群改
在整体改的基础上 添加参数 partial=True
book_ser = serializers.BookModelSerializer(instance=book_instance, data=request.data, partial=True, context={'request': request})
book_ser = serializers.BookModelSerializer(instance=book_query, data=request_data, many=True, partial=True)
ListSerializer分析(重点)
-
modelSerializer : 有 create(单增加) 有 update (单修改)
-
ListSerializer: 有 create(群增加) 没有 update(群修改)
-
ModelSerializer
默认配置了ListSerializer
辅助类 只要你群增 或 群改 都会走ListSerializer
()
配置辅助类
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
# ModelSerializer默认配置了ListSerializer辅助类,帮助完成群增群改
# 使用list_serializer_class = serializers.ListSerializer 可指定ListSerializer
# 如果只有群增,是不需要自定义配置的,但要完成群改,必须自定义配置
list_serializer_class = BookListSerializer
自定义的群增群改辅助类
class BookListSerializer(serializers.ListSerializer):
# 群增
# 自定义的群增群改辅助类,没有必要重写create方法
def create(self, validated_data):
return super().create(validated_data)
# 群改
def update(self, instance_list, validated_data_list):
return [
self.child.update(instance_list[index], attrs) for index, attrs in enumerate(validated_data_list)
] # self.child 其实就是你当前自定义的serializers
吾虽浪迹,却未迷失本心