• 序列化模块


    新建项目准备

    三流

    标准输出流, 标准输入流, 标准错误流

    '''
    C:...d_projscript	est.py
    import sys
    
    sys.stdout.write('123
    ')  # 默认不换行
    sys.stdout.write('456
    ')
    # 123123
    
    # res = sys.stdin.readline()  # 类似于input, 会暂停程序
    # print(res)
    
    sys.stderr.write('789
    ')  # 打印结果飘红, 默认不换行
    sys.stderr.write('101112
    ')
    # 异步执行, 但123与456共用一个流, 456一定在123后, 同理101112一定在789后
    
    
    # C:...d_projapiexception.py
    ...
    def exception_handler(exc, context):
        ...
        import sys
        sys.stderr.write('异常: %s
    ' % response.data.get('detail'))
        ...
    '''
    

    内部类

    '''
    class A:
        class B:  # B类的名称空间通过A类访问
            x = 10
    
    
    print(A.B.x)  # 10
    
    
    # C:...d_projapimodels.py
    ...
    class User(models.Model):
        SEX_CHOICES = (
            (1, '男'),  # 元组的第一个元素存入数据库的对应字段, 第二个元素对第一个元素作说明
            (0, '女')
        )
    
        # verbose_name 可以修改django admin 后台显示的字段名, blank=True表示django admin后台该字段可以不填写
        username = models.CharField(max_length=64, verbose_name='用户名', blank=True)
    
        password = models.CharField(max_length=64, verbose_name='密码')
        sex = models.IntegerField(choices=SEX_CHOICES, default=1, verbose_name='性别')
        avatar = models.ImageField(upload_to='img', default='default.png', verbose_name='头像')  # ImageField继承FileField
        is_delete = models.BooleanField(default=False, verbose_name='是否注销')  # 开发中数据不会直接删除, 而是通过字段控制
        created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
        class Meta:  # 配置类, 给所属类提供配置信息
            db_table = 'old_boy_user'  # 修改数据库显示的表名, 默认值: 所属app_类名小写
            verbose_name_plural = '用户表'  # 修改django admin 后台显示的表名
    
        def __str__(self):
            return self.username  # __str__方法内不能进行联表操作
            
    
    # C:...d_projapiadmin.py
    ...
    from . import models
    
    admin.site.register(models.User)  # 在django admin后台注册User表
    '''
    

    在视图类中手动完成序列化操作

    '''
    # C:...d_projapiviews.py
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from . import models
    from d_proj import settings
    
    
    class UserV1APIView(APIView):
        # 单查群查
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                user_dic = models.User.objects.filter(is_delete=False, pk=pk).values('username', 'sex', 'avatar').first()
                if not user_dic:
                    return Response({'status': 1, 'msg': 'pk error', }, 400)
                    
                user_dic['avatar'] = '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('avatar'))
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'result': user_dic
                })
    
            else:
                ...
    
    '''
    

    Serializer序列化

    序列化

    1. 后端orm操作得到数据
    2. 将数据序列化成可以返回给前端的数据类型
    3. 返回数据给前端

    封装

    面向对象封装

    • 数据需要多个方法处理,
    • 入口为类中的 __init__ 方法

    面向过程封装:

    • 一个方法完成数据处理
    '''
    # C:...d_projapiviews.py
    from . import serializers
    from . import models
    
    
    class UserV2APIView(APIView):
        # 单查群查
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                ...  # user_obj为空时, 也能处理, 结果: 所有字段为空
    
            else:
                # 将对象对外提供的字段, 以及整个序列化过程封装, 形成序列化类
                user_queryset = models.User.objects.filter(is_delete=False).all()
    
                # 根据源码, 当处理的数据中的包含多个对象时需要设置many=true
                user_ser = serializers.UserSerializer(user_queryset, many=True)  # 序列化后的对象
                user_list = user_ser.data  # 序列化后的数据
    
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'result': user_list
                })
                
    
    # C:...d_projapiserializers.py
    from rest_framework import serializers
    from django.conf import settings
    
    
    class UserSerializer(serializers.Serializer):
        """
        	1. UserSerializer类中没有写的但是model表中有的字段不会序列化, 即不会在前端展示
            2. 字段名与字段类型要与对应模型表中的字段名与字段类型一致
            3. 可以自定义序列化字段, 用来调整对应的数据库字段返回给前端的数据, 
            4. 自定义序列化字段一定不参与反序列化
            4. 不建议自定义系列化字段名与数据库字段名重名
            5. 通过在类中自定义方法提供给自定义字段所需的字段值, 方法名为get_自定义字段名
        """
        ...
        sex = serializers.IntegerField()  # "sex": 1,
        avatar = serializers.ImageField()  # "avatar": "/media/img/111.jpg",
        
        gender = serializers.SerializerMethodField()  # "icon": "http://127.0.0.1:8000/media/img/111.jpg"
        icon = serializers.SerializerMethodField()  # "gender": "男"
    
        def get_gender(self, obj):  # obj为参与序列化的数据中的一个对象
            return obj.get_sex_display()
    
        def get_icon(self, obj):  # 在高级序列化与高级视图类中, drf默认序列化处理图片等子资源
            return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, obj.avatar)
            
    
    # G:...
    est_frameworkserializers.py
    class BaseSerializer(Field):
        ...
        def __init__(self, instance=None, data=empty, **kwargs):
            ...
            kwargs.pop('many', None)
            ...
            
            
    class Serializer(BaseSerializer, ...):
    	...  # 该类中没有__init__方法
    '''
    

    Serializer反序列化

    反序列化

    1. 从请求对象中获取前端提交的数据
    2. 序列化类完成数据的反序列化及校验
    3. 序列化类将反序列化后的数据同步到数据库
    4. 将处理结果反馈给前端
    '''
    # C:...d_projapimodels.py
    ...
    class User(models.Model):
        ...
        username = models.CharField(..., unique=True)  # unique=True, 数据库层次限制不能有重复的用户名
        
        
    # C:...d_projapiviews.py
    ...
    class UserV2APIView(APIView):
        ...
        def post(self, request, *args, **kwargs):
            request_data = request.data  # 从请求对象中获取前端提交的数据
            user_ser = serializers.UserDeSerializer(data=request_data)  # 反序列化及校验
    
            if user_ser.is_valid():  # 判断数据校验是否通过
    
                # 根据源码, save方法会判断具体是create还是update, 但因为没有绑定model中的数据库表, 所以没有具体实现方法
                user_obj = user_ser.save()  # 执行save方法会判断并执行对应的数据库操作, 返回操作后得到的新的数据对象
    
                return Response({'status': 0, 'msg': 'ok', 'result': serializers.UserSerializer(user_obj).data}, )
            else:
                return Response({'status': 1, 'msg': user_ser.errors, }, )
                
                
    # C:...d_projapiserializers.py
    from . import models
    
    
    class UserDeSerializer(serializers.Serializer):
        # 系统校验字段
        username = serializers.CharField(min_length=3, max_length=16, error_messages={  # 自定义校验出错的报错信息
            'min_length': '太短',
            'max_length': '太长'
        })
        ...
    
        # required=False的字段前端不提供则使用model表指定的默认值, 提供了则进行反序列化及校验
        sex = serializers.BooleanField(required=False)  # required参数默认值为True
    
        # 自定义校验字段, 语法与系统字段没有区别, 但是需要在全钩子中将其取出, 不保存到数据库,
        re_password = serializers.CharField(min_length=3, max_length=16)
    
        # 局部钩子: 方法名为validate_校验的字段名
        def validate_username(self, value):  # values为通过系统校验后的对应字段值
            # print(value)  # egon
            if 'g' in value:
                raise serializers.ValidationError('用户名不能包含g')
    
            return value  # 字段值符合局部钩子的校验规则, 则将其返回
    	
    	# 全局钩子: 通常用来进行多个字段的校验
        def validate(self, attrs):  # attrs为通过系统校验后的所有字段及字段值
            # print(attrs)  # OrderedDict([('username', 'nick'), ...])
            password = attrs.get('password')
            re_password = attrs.pop('re_password')  # 获取并去除自定义校验字段
            if password != re_password:
                raise serializers.ValidationError({'re_password': '两次密码不一致'})  # key指定错误的字段
                
            return attrs  # 所有数据符合全局钩子的校验规则, 则将其返回
    
        def create(self, validated_data):
            return models.User.objects.create(**validated_data)
    
        def update(self, instance: models.User, validated_data):  # instance为要被修改的数据对象, validated_data为校验后用来修改instance的数据
            models.User.objects.filter(pk=instance.id).update()  # update方法的返回值为受影响的行
            return instance
    '''
    

    ModerSerializer序列化

    '''
    # C:...d_projapiserializers.py
    # ModelSerializer自动处理文件对象的完整路径拼接
    class UserModelSerializer(serializers.ModelSerializer):  
        # # 自定义序列化字段的方式一, 但是定义了不序列化会报错, 无法实现插拔式
        # gender = serializers.SerializerMethodField() 
    
        # def get_gender(self, obj):
        #     return obj.get_sex_display()
    
        class Meta:  # 配置类
            model = models.User  # UserModelSerializer要操作的表
            fields = ('username', 'gender', 'icon')  # 要序列化的字段, 元组形式
    
    
    # C:...d_projapimodels.py
    ....
    class User(models.Model):
        ...
        @property
        def gender(self):  # 自定义序列化字段的方式二, 不仅可以实现插拔式设计而且可以联表操作
            return self.get_sex_display()
    
        @property
        def icon(self):
            from django.conf import settings
            return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, self.avatar)
    
    
    # C:...d_projapiviews.py
    class UserV3APIView(APIView):
        # 单查群查
        def get(self, request, *args, **kwargs):
            ...
                user_ser = serializers.UserModelSerializer(user_obj, many=False)  # 单查序列化
                ...
                # 根据源码, 当处理的数据中的包含多个对象时需要设置many=true
                user_ser = serializers.UserModelSerializer(user_queryset, many=True)  # 群查序列化
                ...
    '''
    

    ModerSerializer反序列化

    '''
    C:...d_projapiserializers.py
    # 根据源码UserModelSerializer对create和update进行了具体实现, 并且支持所有关系下的联表操作
    class UserModelSerializer(serializers.ModelSerializer):  
        ...
        # 自定义反序列化校验字段, 同Serializer, 且校验规则要么在定义时设置, 要么在钩子中设置, 在extra_kwargs中设置的无效
        re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)  # 自定义反序列化字段必须设置write_only
    
        class Meta:
            model = models.User  # UserModelSerializer要操作的表
            fields = ('username', 'gender', 'icon', 'password', 'sex', 're_password')  # UserModelSerializer要操作的字段, 元组形式
    
            extra_kwargs = {  # 设置额外参数将反序列化与序列化区分开来
                'username': {  # 系统字段如果不设置, 默认都参与
                    'min_length': 3,
                    'max_length': 10,
                },
                'password': {  # 只参与反序列化
                    'write_only': True,
                    'min_length': 3,
                    'max_length': 16,
                },
                'gender': {'read_only': True},  # 自定义的序列化字段默认就是read_only, 且不能修改, 但可以省略
                'sex': {  # 有默认值的字段为选填字段, 'required': True可以设置为必填字段
                    'write_only': True,
                    # 'required': True,
                },
            }
    
        # 局部钩子和全局钩子同Serializer, 和Meta同缩进
        ...
        
    
    # C:...d_projapiviews.py
    class UserV3APIView(APIView):
        ...
        def post(self, request, *args, **kwargs):
            ...
            user_ser = serializers.UserModelSerializer(data=request_data)  # ModelSerializer反序列化及校验
            
            user_ser.is_valid(raise_exception=True)  # 校验不通过时, 系统会自动抛错
            ...
    '''
    
  • 相关阅读:
    避免使用HttpClient的系统代理
    C#使用ILGenerator动态生成函数
    leveldb和fork的初始化顺序
    模拟阻尼运动
    [c++]printf的编译器静态检测
    Git Submodule管理项目子模块
    redis 读写分离主从服务类借鉴
    git pull 冲突
    git log 查看提交记录
    自带单例模式的redis类
  • 原文地址:https://www.cnblogs.com/-406454833/p/12118374.html
Copyright © 2020-2023  润新知