• DRF 03


    序列化家族

    • 序列化就是将对象的状态信息转换为可以存储或传输的形式的过程
    """
    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
                })
    
    

    Serializers序列化与反序列化

    序列化

    • 字段设置: 要同模型类的字段对应
    • 自定义序列化字段:
      • 字段类型为: 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序列化与反序列化

    • 继承了ModelSerialzer类, 需要在配置类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
                })
    
  • 相关阅读:
    [GoogleInterview]连续子序列问题
    [Codeforces #615 div3]1294E Obtain a Permutation
    重识线段树——Let's start with the start.
    [易语言][ExDui][Tutorial]1.NameSelector
    [LuoguP1025][数据加强]数的划分
    [易语言][ExDui][Tutorial]0.Hello,world!
    Hello,cnblog!
    棋牌覆盖问题(分治)
    UVA 11732题解
    LA 3942Remember the Word
  • 原文地址:https://www.cnblogs.com/bigb/p/12099880.html
Copyright © 2020-2023  润新知