• Django框架之drf 之一 [restful规范 APIview源码分析 Request类分析 序列化组件 ]


    Django框架drf之 restful规范 APIview源码分析 Request类分析 序列化组件

    一、restful规范 

    1 Representational  State  Transfer:表征性状态转移
    2 Web  API接口的设计风格,尤其适用于前后端分离的应用模式中
    3 与语言,平台无关,任何框架都可以写出符合restful规范的api接口
    4 规范:10条(记住常用四五条即可1  数据的安全保障:url链接一般都采用https协议进行传输
        2  接口特征表现: api关键字标识
            -https://api.baidu.com/books/
            -https://www.baidu.com/api/books/
         3  多版本共存:url链接中标识接口版本
            -https://api.baidu.con/v1/books/
            -https://api.baidu.con/v2/books/
         4  数据即是资源,均使用名词(可复数)*********
            -接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
            -一般提倡用资源的复数形式,不要使用动词
            -查询所有图书
                -https://api.baidu.com/books/
                -https://api.baidu.com/get_all_books/   #错误示范
                -https://api.baidu.con/delete-user    /    #错误示范
                -https://api.baidu.com/user              ## 删除用户的示例:疑问:到底是删还是查?(看用什么方式访问)
          5 资源操作由请求方式决定:
            https://api.baidu.com/books       - get请求:获取所有书
            https://api.baidu.com/books/1     - get请求:获取主键为1的书
            https://api.baidu.com/books       - post请求:新增一本书书
            https://api.baidu.com/books/1     - put请求:整体修改主键为1的书
            https://api.baidu.com/books/1     - patch请求:局部修改主键为1的书
            https://api.baidu.com/books/1     - delete请求:删除主键为1的书
           6 过滤,通过在url上传参的形式传递搜索条件
            https://api.example.com/v1/zoos?limit=10         :指定返回记录的数量
            https://api.example.com/v1/zoos?offset=10&limit=3:指定返回记录的开始位置
            https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
            https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
            https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
          7  响应状态码
            -返回数据中带状态码
            -{'code':100}
           8 返回结果中带错误信息
            -{'code':100,'msg':'因为xx原因失败'}  
           9 返回结果,该符合以下规范
            GET /collection:返回资源对象的列表(数组)
            GET /collection/resource:返回单个资源对象(字典)
            POST /collection:返回新生成的资源对象    (新增后的对象字典)
            PUT /collection/resource:返回完整的资源对象 (修改后的对象字典)
            PATCH /collection/resource:返回完整的资源对象 (修改后的对象字典)
            DELETE /collection/resource:返回一个空文档   ()
    
    
            10 返回的数据中带链接地址
            -查询id为1的图书接口,返回结果示例
            {'code':100,
             'msg':'成功',
             'result':
                 {'title':'金瓶密钥',
                  'price':12.3,
                  'publish':'https://127.0.0.1/api/v1/publish/3'
                 }
            }
     
                                            

    2 APIview源码分析

    1  APIview的as_view
        内部还是执行了View的闭包函数view
        禁用掉了csrf
        一切皆对象,函数也是对象  函数地址.name=lqz
    2原生的View类中的as_view中的 闭包函数view
        -本质执行了self.dispatch(reqiest,*args,**kwargs),执行的是APIView的dispath
    3 APIView的dispatch
            def dispatch(self,*args,**kwargs):
            #DRF的Request类的对象,内部有request._request,是原生request
            request(已经不是原生的Request了) = self.initialize_request(request(是原生的),*args,**kwargs)
            self.request = request
            try:
                self.initial(request, *args, **kwargs)
                '''
                #认证,权限,频率
                self.perform_authentication(request)
                self.check_permissions(request)
                self.check_throttles(request)
                '''
                if request.method.lower() in self.http_method_names:
                    handler = getattr(self, request.method.lower(),
                                      self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
    
                response = handler(request, *args, **kwargs)
    
            except Exception as exc:
                # 全局的异常捕获
                response = self.handle_exception(exc)
            # 把视图函数(类)返回的response,又包装了一下
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response
    重要:
    分析:当请求过来,进入url中的路由,执行Books.as_view()得到原生View中的view,最后加括号执行view(),执行view中的self.dis_pach,因为是Books的对象调用,所以先去Books类中找dis_pach,没有再去APIView中找,
    在APIView中找到并执行,在dis_pach中执行了initialize_request,将原生的request替换成了drf中的request.且在drf中将原生request储存成了_request。


    三 Request类分析

    1 Request类
        -request._request:原生request
        -request.data:post请求提交的数据(urlencoded,json,formdata)
        -request.user:不是原生的user了
        -request.query_paras:原生的request.GET,为了遵循restful规范
        -request.FIFES:新的
        -重写了__getattr__,新的request.原来所有的属性和方法,都能直接拿到
            def __getattr__(self,attr):
                    return  getattr(self._request,attr)

    四。序列化组件

      1 序列化组件介绍

    1:序列化作用:
      1 进行数据校验
      2 对数据对象进行转换
      


    2 作用: 1.序列化,序列化器会把模型对象转成字典,经过request以后变成json字符串 -Book--序列化器---->字典--通过drf:Response-->json格式字符串-->传给前端 用于输出 2 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型 json格式数据--drf:Request--》字典---序列化器---》Book 用于输入 3 反序列化,完成数据校验功能

    总结 :
    在开发REST API接口时,我们在视图中需要做的最核心的事是:
    将数据库数据序列化为前端所需要的格式,并返回; 
    将前端发送的数据反序列化为模型类对象,并保存到数据库中
    在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:
    增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    删:判断要删除的数据是否存在 -> 执行数据库删除
    改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    查:查询数据库 -> 将数据序列化并返回

      2 序列化组件简单使用

    1 序列化的使用
        -写一个序列化类继承serializers.Serializer
            -在类中写要序列化的字段
            -在视图类中,实例化得到一个序列化类的对象,把要序列化的数据传入
                ser=BookSerializer(instance=res,many=True)
            -得到字典
                ser.data就是序列化 后的字典


    注意:
    ser=BookSerializer(instance=res,many=True)
    表示序列化,需要传入的是instance(对象),many=True,表示可以多个
    ser=BookSerializer(data=request.data)
    表示反序列化,需要传入的是前端传过来的数据,经过序列化器后变成对象,存入数据库

    ser=BookSerializer(data=request.data,instance=res,many=False)
    表示修改,需要前端传输过来的数据,以及后端传过来的对象,




    2.1 代码实现

    serializer.py

    from rest_framework import serializers
    class  BookSerializer(serializers.Serializer):
        #要序列化那个字段
        id=serializers.IntegerField()
        title=serializers.CharField(max_length=32)
        price=serializers.DecimalField(max_digits=5,decimal_places=2)
       publish=serializers.CharField(max_length=32)

    models.py

    class Book(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        price=models.DecimalField(max_digits=5,decimal_places=2)
        publish=models.CharField(max_length=32)

    views.py

    from app01  import models
    from app01.serializer import BookSerializer
    class  Book(APIView):
        def get(self,request,*args,**kwargs):
            res = models.Book.objects.all()
            #借助于序列化器
            #如果是多条,就是many=True
            #如果是单个对象,就不写
            ser=BookSerializer(instance=res,many=True)
            #通过序列化器得到的字典
            #ser.data
            print(ser.data)
            return Response(ser.data)

    urls.py

    path('books/',views.Book.as_view())

    3 序列化类字段类型和字段参数

      

    # 字段类型(记列的这几个)
        -IntegerField
        -CharField
        -DecimalField
        -DateTimeField
        -。。。跟models中大差不差
        
    # 常用字段参数
        -选项参数
            max_length    最大长度
            min_lenght    最小长度
            allow_blank    是否允许为空
            trim_whitespace    是否截断空白字符
            max_value    最小值
            min_value    最大值
        
        -通用参数
            #重点
            read_only    表明该字段仅用于序列化输出,默认False
            write_only    表明该字段仅用于反序列化输入,默认False
            
            # 掌握
            required    表明该字段在反序列化时必须输入,默认True
            default        反序列化时使用的默认值
            allow_null    表明该字段是否允许传入None,默认False
            
            # 了解
            validators    该字段使用的验证器
            error_messages    包含错误编号与错误信息的字典
        

    4 序列化器的保存功能

    #如果序列化类继承的是Serializer,必须重写create方法
    #使用方式
        -视图类
            def post(self,request):
                print(request.data)
                ser=BookSerializer(data=request.data)   #ser此时是一个对象
                if ser.is_valid():
                    ser.save()  #保存到数据库中
                    return Response(ser.data)
                else:
                    #没有校验通过的错误信息
                    return Response(ser.errors)
         -序列化类
        class BookSerializer(serializers.Serializer):
            ...
            def create(self,validated_data):
            #为甚摸要重写create???
                  res=models.Book.objects.create(**validated_data)
                  print(res)
                  return  res
        
                
                                             

    5 序列化器的字段校验功能

    #三种方式
        -字段自己的校验规则(max_length...)
        -validators的校验
            publish = serializers.CharField(max_length=32,validators=[check,])
            
    
            def check(data):
                if len(data)>10:
                    raise  ValidationError('最长不能超过10')
                else:
                    return  data
    
            -局部和全局钩子
    # 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据
        def validate_title(self, data):
            if data.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return data
        # 全局钩子
        def validate(self, attrs):
            title=attrs.get('title')
            publish=attrs.get('publish')
            if title==publish:
                raise ValidationError('书名不能跟出版社同名')
            else:
                return attrs

    6 read_only和write_only

    read_only  表名该字段仅用于序列化输出,默认False
    write_only  表名该字段仅用于反序列化输入,默认False
    class BookSerializer(serializers.Serializer):
            # 要序列化哪个字段   required=False 可以在反序列化的时候不使用该字段
            id = serializers.IntegerField(required=False)
            # id=serializers.CharField()
            title = serializers.CharField(max_length=32,min_length=2,read_only=True)
            price = serializers.DecimalField(max_digits=5, decimal_places=2)
            # 序列化的时候看不到
            publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)
        

     注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义

      1.在用于序列化时,将模型类对象传入instance参数

      2.在用于反序列化时,获取数据前进行验证(is_avled()),将要被反序列化的数据传入data参数

  • 相关阅读:
    python读取配置文件之.ini后缀文件
    Qt界面中打开图片的一个小bug
    C++指针与数组、函数、动态内存分配
    使用VS调试安卓Unity应用
    VS2017调试Unity时遇到的“未指定错误”解决方法记录
    【5】用vector进行直接插入排序
    【4】数独(Sudoku Killer)(深度优先遍历)
    【3】素数环问题(递归、搜索)
    【2】展开字符串(栈、递归)
    【1】简单计算器(栈)
  • 原文地址:https://www.cnblogs.com/ltyc/p/13926509.html
Copyright © 2020-2023  润新知