day 74 DRF 序列化 Serializer与ModelSerializer的序列化和反序列化
DRF
序列化家族
- 序列化:将对象的状态信息转换为可以存储或传输的形式的过程
"""
1.Serializer类:底层序列化类 - 了解类
重点:单表序列化
2.ModelSerializer:模型序列化类 - 核心类
重点:多表序列化
3.ListSerializer:群操作序列化类 - 辅助类
重点:辅助完成单表多表群增群改操作
"""
手动实现序列化
- 这里的手动实现指的是将对象信息传输到前端
# 1.自定义序列化版本
class UserV1APIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
print(pk)
# 单查
if pk:
user_dic = models.User.objects.filter(is_delete=False, pk=pk).values('username', 'gender', 'avatar').first()
# 查询不到时
if not user_dic:
return Response(
{'status': 1, 'msg': 'id error'},
status=status.HTTP_400_BAD_REQUEST
)
# 对头像路径进行拼接
user_dic['avatar'] = f"{settings.BASE_URL}{settings.MEDIA_URL}{user_dic.get('avatar')}"
return Response({
'status': 0,
'msg': 'ok',
'results': user_dic
})
# 群查
else:
user_query = models.User.objects.filter(is_delete=False).values('username', 'gender', 'avatar')
for user_dict in user_query:
# 对头像路径进行拼接
user_dict['avatar'] = f"{settings.BASE_URL}{settings.MEDIA_URL}{user_dict.get('avatar')}"
user_list = list(user_query)
return Response({
'status': 0,
'msg': 'ok',
'results': user_list
})
Serializer序列化与反序列化
序列化
- 字段设置:要同模型类的字段对应
- 自定义序列化字段
- 字段类型为:
SerializerMethodField()
- 字段名不应和模型类字段名冲突
- 通过定义
get_自定义字段名(self, obj)
方法来获取要序列化的值
- 字段类型为:
"""
1.新建一个serializers.py文件
2.导入: from rest_framework import serializers
3.新建一个类, 继承serializers.Serializer
4.在类中添加需要序列化的字段, 字段名要与模型类中的字段相对应
5.自定义的字段不应该和模型类字段重名, 通过定义 'get_字段名' 方法来获取要序列化的值
"""
# serializers.py中定义
class UserSerializer(serializers.Serializer):
# 字段名要与模型类中的字段相对应
username = serializers.CharField()
# 自定义序列化字段需要两个参数: self和obj(模型类对象)
# 自定义序列化字段不应与模型类字段重合, 通过'get_自定义字段名'方法获取值进行序列化
user_gender = serializers.SerializerMethodField()
def get_user_gender(self, obj):
return obj.get_gender_display()
user_avatar = serializers.SerializerMethodField()
def get_user_avatar(self, obj):
return f"{settings.BASE_URL}{settings.MEDIA_URL}{obj.avatar}"
----------------------------------------------------------------------------------------------------
"""
视图类序列化过程
1)ORM操作得到数据
2)将数据序列化成可以返回给前台的数据
3)返回数据给前台
"""
# views.py中使用
class UserV2APIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 单查
if pk:
user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
# 查询不到时
if not user_obj:
return Response(
{'status': 1, 'msg': 'id error'},
status=status.HTTP_400_BAD_REQUEST
)
# 传入数据对象, 生成序列化对象
serializer_obj = serializers.UserSerializer(user_obj, many=False)
return Response({
'status': 0,
'msg': 'ok',
# 序列化后数据存放在序列化对象的data属性中
'results': serializer_obj.data
})
# 群查
user_query = models.User.objects.filter(is_delete=False).all()
# 当序列化多个数据对象时, 要设置 many=True
serializer_obj = serializers.UserSerializer(user_query, many=True)
return Response({
'status': 0,
'msg': 'ok',
# 序列化后数据存放在序列化对象的data属性中
'results': serializer_obj.data
})
反序列化
- 自定义字段和普通字段的设置内有区别
- 自定义字段不能直接入库, 需要设置入库规则, 或在钩子中将其移除
- 局部钩子:
validate_字段名(self, value)
value是字段的值- 通过校验返回value, 否则抛出错误信息:
raise serializers.ValidationError({'字段名': '错误信息'})
- 全局钩子:
validate(self, attrs)
attrs是包含字段(键)和字段值(值)的字典- 通过校验返回attrs, 否则抛出错误信息:
raise serializers.ValidationError({'字段名': '错误信息'})
- 重写create方法实现增入库,返回入库成功的对象
- 重写update方法实现改入库,返回入库成功的对象
# Serializer反序列化
class UserDeSerializer(serializers.Serializer):
username = serializers.CharField(min_length=3, max_length=12, error_messages={
'min_length': '不能少于三个字符',
'max_length': '不能长于12个字符',
})
password = serializers.CharField(min_length=3, error_messages={
'min_length': '不能少于三个字符',
})
# 只要有该字段, 则就必须参与反序列化, 可以通过required=False设置不参与
gender = serializers.BooleanField(required=False)
# 自定义校验字段, 不参于入库操作, 需要在全局钩子中取出
re_password = serializers.CharField(min_length=3, error_messages={
'min_length': '不能少于三个字符',
})
# 局部钩子
def validate_username(self, value):
if value.lower() == 'bigb':
raise serializers.ValidationError('不能和我同名!')
return value
# 全局钩子
def validate(self, attrs):
password = attrs.get('password')
re_password = attrs.pop('re_password')
if not password == re_password:
raise serializers.ValidationError({'re_password': '密码输入不一致'})
return attrs
# 增加操作
def create(self, validated_data):
return models.User.objects.create(**validated_data)
# 修改操作
def update(self, instance, validated_data):
# 用户名不能被修改
validated_data.pop('username')
models.User.objects.filter(pk=instance.id).update(**validated_data)
return instance
----------------------------------------------------------------------------------------------------
"""
# 视图类反序列化过程
# 1)从请求对象中获取前台提交的数据
# 2)交给序列化类完成反序列化(数据的校验)
# 3)借助序列化类完成数据入库
# 4)反馈给前台处理结果
"""
# 单增
def post(self, request, *args, **kwargs):
request_data = request.data
print(request_data)
serializer_obj = serializers.UserDeSerializer(data=request_data)
if serializer_obj.is_valid():
# 通过save()方法进行入库
user_obj = serializer_obj.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.UserSerializer(user_obj).data
})
else:
return Response({
'status': 1,
'msg': serializer_obj.errors
})
ModelSerializer序列化与反序列化
-
继承了ModelSerializer类,需要在配置类Meta中进行配置
- model:绑定模型类
- field:设置所有参与序列化与反序列化的字段
- extra_kwargs:
- 划分系统字段为三种:read_only, write_only, 不设置(可读可写)
- 字段限制条件
-
自定义序列化字段
- 在序列化类中用SerializerMethodField()来实现
- 在模型类中用@property自定义方法属性来实现(可插拔)
-
自定义反序列化字段
- 同Serializer类,且限制条件只能在此声明,或者在钩子中进行判断,不能在extra_kwargs进行设置
-
局部钩子和全局钩子同Serializer类一样
-
不需要重新create和update方法
# ModerSerializer序列化与反序列化
class UserModelSerializer(serializers.ModelSerializer):
# 第一种自定义序列化字段方法, 必须在fields中设置
# user_gender = serializers.SerializerMethodField()
#
# def get_user_gender(self, obj):
# return obj.get_gender_display()
# 自定义反序列化字段同Serializer中一致, 且校验规则只能一并声明, 或者在钩子判断, 在extra_kwargs设置无效
re_password = serializers.CharField(min_length=3,
error_messages={'min_length': '不能少于三个字符'},
write_only=True)
class Meta:
# 绑定模型表
model = models.User
# 设置所有参与序列化与反序列化的字段(插拔式设计)
fields = ('username', 'password', 'user_gender', 'gender', 'user_avatar', 're_password')
extra_kwargs = {
# 不设置write_only和read_only表名该字段可读可写
'username': {
'min_length': 3,
'max_length': 12,
'error_messages': {
'min_length': '不能少于3个字符',
'max_length': '不能长于12个字符',
}
},
'password': {
'write_only': True
},
'user_gender': {
# 自定义的序列化字段默认就是read_only, 且不能修改
'read_only': True
},
'gender': {
'write_only': True,
'required': False,
}
}
# 局部钩子与Serializer一致
def validate_username(self, value):
if value.lower() == 'bigb':
raise serializers.ValidationError('不能和我同名!')
return value
# 全局钩子与Serializer一致
def validate(self, attrs):
password = attrs.get('password')
re_password = attrs.pop('re_password')
if not password == re_password:
raise serializers.ValidationError({'re_password': '密码输入不一致'})
return attrs
----------------------------------------------------------------------------------------------------
# ModelSerializer序列化与反序列化
class UserV3APIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 单查
if pk:
user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
# 查询不到时
if not user_obj:
return Response(
{'status': 1, 'msg': 'id error'},
status=status.HTTP_400_BAD_REQUEST
)
# 传入数据对象, 生成序列化对象
serializer_obj = serializers.UserModelSerializer(user_obj, many=False)
return Response({
'status': 0,
'msg': 'ok',
# 序列化后数据存放在序列化对象的data属性中
'results': serializer_obj.data
})
# 群查
user_query = models.User.objects.filter(is_delete=False).all()
# 当序列化多个数据对象时, 要设置 many=True
serializer_obj = serializers.UserModelSerializer(user_query, many=True)
return Response({
'status': 0,
'msg': 'ok',
'results': serializer_obj.data
})
# 单增
def post(self, request, *args, **kwargs):
request_data = request.data
print(request_data)
serializer_obj = serializers.UserModelSerializer(data=request_data)
if serializer_obj.is_valid():
# 通过save()方法进行入库
user_obj = serializer_obj.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.UserSerializer(user_obj).data
})
else:
return Response({
'status': 1,
'msg': serializer_obj.errors
})