zoukankan      html  css  js  c++  java
  • drf框架序列化和返序列化

    0903自我总结

    drf框架序列化和反序列化

    from rest_framework import serializers

    一.自己对于序列化和反序列化使用的分类

    前后端交互主要有get,post,puch,put,deleter

    其中用到序列化的get

    用到反序列化的剩下四中

    二.序列化的使用

    1.首先我们要根据我们定义的模型一一对应定义一个继承serializers.Serializer的类

    class UserSerializer(serializers.Serializer):
        username = serializers.CharField()
    	#不需要的字段=serializers.CharField(write_only=True)
        sex = serializers.IntegerField()
    
        gender = serializers.SerializerMethodField()
        def get_gender(self, user_obj):
            return user_obj.get_sex_display()
        
        icon = serializers.SerializerMethodField() #SerializerMethodField为自定义字段
        def get_icon(self, user_obj):
            icon_url = 'http://127.0.0.1:8000{}{}'.format(settings.MEDIA_URL, user_obj.icon)
            return icon_url
    

    自定义字段,拿gander字段举例在models中是

    SEX_CHOICES = [
        (0, '男'),     #choices选择中,括号里前者表示填写的值,后者表示对应的值
        (1, '女'),
    ]
    # 为choices的字段,获取值后的映射关系 get_字段名_display()
    sex = models.IntegerField(choices=SEX_CHOICES, default=0)
    
    def get_gender(self, user_obj):
        return user_obj.get_sex_display()
    
    基于GET请求的get_固定写法
    def get_model类中有字段(self,obj):
        #逻辑处理
        return 修改后的代码
    

    需要序列化字段

    • 在不做任何处理的情况下我们定义的类里面的字段必须在model类中必须存在该字段
    • 参与序列化的属性名必须与model类的属性相同
    • 只出现在序列化中不出现在反序列化中我们要加只读属性read_only=True
    • 如果我们Serializer类中定义字段类型为SerializerMethodField自定义字段类型不用遵守类里面的字段必须在model类中必须存在该字段

    不需要序列化字段

    • 不需要序列化的属性字段在序列化类中不需要声明
    • 不需要序列化的属性字段在序列化类中设置只写属性write_only=True

    2.在views视图中

    from rest_framework.views import APIView
    class UserAPIView(APIView):
         def get(self, request, *args, **kwargs):
            user_obj = models.User.objects.all().frist
    		user_obj_data = '''我们自定义的Serializer类'''(user_obj).data
    		return APIResponse(0, 'ok', results=user_obj_data)
    
    • 获取models中的对象
    • 我们自定义的Serializer类传入models中的对象然后.data
    • 如果models中对象为多个Serializer传入models中的对象以外many=True还需传入这个参数
    • many这个参数默认是False所有我们序列化单个参数时候不需要传入many
    • 序列化数据可以为状态User类的多个对象的单列集合,不能是多列集合

    :

    • 单列集合[a,b,c.....] |{a,b,c.....}|(a,b,c.....)|QuerySet
    • 多列集合{k1:v1,k2:v2.......}

    三反序列化的使用

    1.首先我们要根据我们定义的模型一一对应定义一个继承serializers.Serializer的类

    class UserDeserializer(serializers.Serializer):
        username = serializers.CharField(
            min_length=3,
            error_messages={
                'min_length': '用户名太短'
            }
        )
        password = serializers.CharField(
            min_length=3,
            error_messages={
                'min_length': '密码太短'
            }
        )
        re_password = serializers.CharField(
            min_length=3,
            required=True,
            error_messages={
                'min_length': '确认密码太短',
                'required': '确认密码不能为空'
            }
        )
    

    相较于序列化定义反序列化中增加了条件的筛选

    注意点:如果类的字段值应用在反序列化,我们可以在他的字段的属性上加上write_only=True

    里面所提及的字段必须传入

    常用的约数条件与django中from组件约数条件有点类似:

    • error_messages 错误信息的属性
    • required是否为空
    • max_length 最长
    • min_length 最短
    • invalid 格式

    局部钩子

    class UserDeserializer(serializers.Serializer):
        .......
        def validate_字段名称(self,value):
            #代码块
            if 情况不满足:
                raise serializers.ValidationError('异常信息') #抛出异常
                return value
            #也就是对字段数据进行二次处理
    

    全局钩子

     class UserDeserializer(serializers.Serializer):
        .......
        def validate(self, attrs):
            #attrs是所有字段的一个类似字典的集合
            #我们要其中某个字段
            attrs.get('字段名')
            return attrs
           # 最终结果抛出异常或者返回attrs
    

    2.内容新增使用

    我们如果想自定义create的相关内容我们可以Serializer类中再加个create方法

    class UserDeserializer(serializers.Serializer):
        .......
        def create(self, validated_data):
            try:
                return modles中的类.objects.create(**validated_data)
            except:
                raise IOError('数据库入库失败')
    

    我们更具需求可以先自定义一个APIResponse,继承rest_framework中的Response也可以直接使用他自带的

    自定义APIResponse,建议自定义

    from rest_framework.response import Response
    """
    Response({
        'status': 0,
        'msg': 'ok',
        'results': [],
        'token': ''
    }, headers={}, status=200, content_type="")
    
    APIResponse(0, 'ok', results, status, headers, content_type)
    """
    
    class APIResponse(Response):
        def __init__(self, data_status, data_msg, results=None,
                     status=None, headers=None, content_type=None, **kwargs):
            data = {
                'status': data_status,
                'msg': data_msg
            }
            if results is not None:
                data['results'] = results
            data.update(kwargs)
            super().__init__(data=data, status=status, headers=headers, content_type=content_type)
    

    在视图函数中的设置

    class UserAPIView(APIView):
    	def post(self, request, *args, **kwargs):  #一般都是post请求
            request_data = request.data
            user_ser = '''我们自定义的Serializer类'''(data=request_data) #传入request.data
            
            
            if user_ser.is_valid():  # 自定义处理校验成功的逻辑
                user_obj = user_ser.save()
                return APIResponse(0, 'ok',
                    results=serializers.UserSerializer(user_obj).data
                )
            else:  # 自定义返回错误信息
                return APIResponse(1, 'failed', results=user_ser.errors)
    

    3.内容修改使用

    我们如果想自定义update的相关内容我们可以Serializer类中再加个update方法

    class UserDeserializer(serializers.Serializer):
       		 .......
        def update(self, instance, validated_data):
            # instance自定义传入的要更新的原数据(pk | obj | queryset)
            # validated_data校验通过后的新数据
            # instance的值外部反序列化传入要更新的自定义标识决定
            instance.update(**validated_data)
            return instance.first()
    

    在视图函数中的设置

    单整体改

    class UserV2APIView(APIView):
        
        def put(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                return APIResponse(1, 'pk error')
    
            user_query = models.User.objects.filter(pk=pk, is_delete=False)
            if not user_query:
                return APIResponse(1, 'user error')
    
            # 第一种:user_query完成数据的更新
            # user_query = models.User.objects.filter(pk=pk)
            # user_query.update(**kwargs)
    
            # 第二种:user_obj完成数据的更新
            # user_obj = models.User.objects.filter(pk=pk).first()  # type: models.User
            # user_obj.username = 'new_username'
            # ...
            # user_obj.save()
      
    
           #这里的instance必须传参(pk | obj | queryset)
            request_data = request.data
            user_ser = serializers.UserV2Serializer(instance=user_query, data=request_data)
            if user_ser.is_valid():
                # save的返回值是由update内部自定义的返回值决定
                user_obj = user_ser.save()
                return APIResponse(0, 'ok',
                    results=serializers.UserV2Serializer(user_obj).data
                )
            else:
                return APIResponse(1, 'failed', user_ser.errors)
    

    单删单体修改

    现在数据都是很重要的一般情况下不会吧数据删除只会做个标记字段其本质还是局部更新

        def delete(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                return APIResponse(1, 'pk error')
            user_obj = models.User.objects.filter(pk=pk, is_delete=False).first()
            if not user_obj:
                return APIResponse(1, '删除失败')
            user_obj.is_delete = True
            user_obj.save()
            return APIResponse(0, '删除成功')
    

    四.model字段修订与时区修改

    model.py

        create_time = models.DateTimeField(auto_now_add=True, null=True)
        is_delete = models.BooleanField(default=False)
    

    setting.py

    时区相关设置

    LANGUAGE_CODE = 'zh-hans'   #其中 zh-Hans是简体中文  zh-Hant是繁体中文
    
    TIME_ZONE = 'Asia/Shanghai'  #上海时间
    
    USE_I18N = True   #国际化支持 I18N
    
    USE_L10N = True
    
    USE_TZ = False   #USE_TZ设置为True,Django会使用系统默认设置的时区即America/Chicago,此时的TIME_ZONE不管有没有设置都不起作用。
    

    注意点:

    USE_TZ为True,TIME_ZONE不管有没有设置都不起作用

  • 相关阅读:
    【Linux基础总结】Linux基本环境
    mysql 源码安装
    windows内存映射文件
    TCHAR和CHAR类型的互转
    删除链表中重复的结点
    iptables防火墙
    两个链表的第一个公共结点
    无人值守安装linux系统
    dns服务 很多问题,后续再研究
    string 类型转换
  • 原文地址:https://www.cnblogs.com/pythonywy/p/11455508.html
Copyright © 2011-2022 走看看