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
            })
posted @ 2019-12-26 16:33  colacheng  阅读(171)  评论(0编辑  收藏  举报
Live2D