zoukankan      html  css  js  c++  java
  • 一、drf入门规范

    drf入门规范

    一、Web一能用模式

    • 前后端混合开发(前后端不分离:全栈):返回来的是html的内容,需要自己写模板
    • 前后端分离:只专注于写后端接口,返回的是json、xml(过时)格式的数据
    • 前后端分离需要中间媒介:api接口

    二、API接口

    • 通过网络,规定前后台信息交互规则的url链接
    • 就是前后端交互的媒介,双方协议好传输数据的格式

    三、Restful规范(重点)

    # REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征性状态转移)。 它首次出现在2000年Roy Fielding的博士论文中。
    
    # uri:资源唯一标识(抽象概念)
    # url:资源唯一定位(具体实现)
    

    RESTful是Web API接口的设计规范风格,这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,尤其适用于前后端分离的应用模式中。

    所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。

    其实,任何一个框架都可以实现符合restful规范的API接口。

    十条规范

    1.数据的安全保障:
    	url链接一般都是采用哪个https协议进行传输
        注:采用https协议,可以提高数据交互过程中的安全性
    2.接口特征表现,一看看就知道是以api接口
    	用api关键字标识接口url
        	https://www.baidu.com/api
    		[https://api.baidu.com](https://api.baidu.com/)
        注:看到api字眼,就代表该请求url链接是完成前后台数据交互的
    3.多数据版本共存
    	在url链接中标识数据版本
        	https://api.baidu.com/v1
        	https://api.baidu.com/v2
        注:url链接中的v1、v2就是不同数据版本的体现(只有在一种数据资源有多版本情况下)
    4 数据即是资源,均使用名词(可复数)#####################重点####################
    	接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
        	https://api.baidu.com/users
        注:一般提倡用资源的复数形式,在url链接中奖励不要出现操作资源的动词
        特殊的接口可以出现动词,因为这些接口一般没有一个明确的资源,或是动词就是接口的核心含义
            https://api.baidu.com/place/search
            https://api.baidu.com/login
    5 资源操作由请求方式决定(method)#####################重点####################
         操作资源一般都会涉及到增删改查,使用请求方式确定操作类型
         	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上传参的形式传递搜索条件,或者说查询参数(query_params)
        - https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
        - https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
        - 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 响应状态码
       7.1 正常响应
        - 响应状态码2xx
          - 200:常规请求
          - 201:创建成功
       7.2 重定向响应
        - 响应状态码3xx
          - 301:永久重定向
          - 302:暂时重定向
       7.3 客户端异常
        - 响应状态码4xx
          - 403:请求无权限
          - 404:请求路径不存在
          - 405:请求方法不存在
    	7.4 服务器异常
        - 响应状态码5xx
          - 500:服务器异常
            
     8 错误处理,应返回错误信息,error当做key
        {
            error: "无权限操作"
        }
        
     9 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范
        GET /collection:返回资源对象的列表(数组)
        GET /collection/resource:返回单个资源对象
        POST /collection:返回新生成的资源对象
        PUT /collection/resource:返回完整的资源对象
        PATCH /collection/resource:返回完整的资源对象
        DELETE /collection/resource:返回一个空文档
        
     10 需要url请求的资源需要访问资源的请求链接
        - Hypermedia API,RESTful API最好做到Hypermedia,
        - 即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么
            {
                "status": 0,
                "msg": "ok",
                "results":[
                    {
                        "name":"肯德基(罗餐厅)",
                        "img": "https://image.baidu.com/kfc/001.png"
                    }
                    ...
                    ]
            }
    

    四、drf的安装和简单使用

    • 安装:pip install djangorestframework==3.10.3

    • 使用

      1. 在settings.py的app中注册

        INSTALLED_APPS = [
           'rest_framework'
        ]
        
      2. 在models.py中写表模型

        class Book(models.Model):
            nid=models.AutoField(primary_key=True)
            name=models.CharField(max_length=32)
            price=models.DecimalField(max_digits=5,decimal_places=2)
            author=models.CharField(max_length=32)
        
      3. 新建一个序列化类(听不懂)

        from rest_framework.serializers import ModelSerializer
        from app01.models import  Book
        class BookModelSerializer(ModelSerializer):
            class Meta:
                model = Book
                fields = "__all__"
        
      4. 在视图中写视图类

        from rest_framework.viewsets import ModelViewSet
        from .models import Book
        from .ser import BookModelSerializer
        class BooksViewSet(ModelViewSet):
            queryset = Book.objects.all()
            serializer_class = BookModelSerializer
        
      5. 写路由关系

        from app01 import views
        from rest_framework.routers import DefaultRouter
        router = DefaultRouter()  # 可以处理视图的路由器
        router.register('book', views.BooksViewSet)  # 向路由器中注册视图集
        # 将路由器中的所以路由信息追到到django的路由列表中
        urlpatterns = [
            path('admin/', admin.site.urls),
        ]
        #这是什么意思?两个列表相加
        # router.urls  列表
        urlpatterns += router.urls
        
      6. 启动,在postman中测试即可

    五、CBV源码阅读

    • 代码分析

      1. 切入点: urls.py中的.as_view()方法

        url(r'^books1/', views.Books.as_view())
        
      2. 视图中Books类

        class Books(View):
            # 如果有个需求,该视图只能接受get请求?
            # 重写http_method_names列表,只保留get请求即可
            http_method_names = ['get']
            
            def get(self,request):
                print(self.request) # 这里可以通过self.request获取到request对象
                return HttpResponse("ok")        
        
      3. 项目启动时执行

        @classonlymethod # 就是classmethod装饰器,django重写了classmethod而已
        def as_view(cls, **initkwargs):
        	...
        
            def view(request, *args, **kwargs):
                ...
        
            ...
            return view
        
      4. 路由匹配时执行, 将执行的类进行实例化, 通过执行路由匹配中类实例化出的对象就可以执行到继承父类View中定义的dispatch方法

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
        
      5. 通过dispatch方法中使用反射获取请求的类型去执行对应类中定义的请求的方法

        def dispatch(self, request, *args, **kwargs):
            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
            return handler(request, *args, **kwargs) # 直接加括号调用handler
        
      6. 上面的self.http_method_names判断, 如果子类中没有派生那么就会通过View中定义的进行判断

        class View(object):
            http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
            ...
        
    • 图示分析

      1. 切入点: urls.py中的.as_view()方法image-20201227201430401

      2. 视图中Books类

        image-20201227201636023

      3. 项目启动时执行

        image-20201227201824849

      4. 路由匹配时执行, 将执行的类进行实例化, 通过执行路由匹配中类实例化出的对象就可以执行到继承父类View中定义的dispatch方法

        image-20201227202012642

      5. 通过dispatch方法中使用反射获取请求的类型去执行对应类中定义的请求的方法

        image-20201227202159850

      6. 上面的self.http_method_names判断, 如果子类中没有派生那么就会通过View中定义的进行判断

        image-20201227202236755

    • 总结

      1. 项目启动: views.Books.as_view()就是View类中的view函数内存地址
      2. 路由匹配: 将view加括号调用, 并传入request对象.
      3. 执行view: 将Books类进行实例化, 实例化出Books类的对象. 这里的self就是Books类实例化出的对象
      4. 执行self.dispatch方法: self就是Books类实例化出的对象, 如果之类以及对象中都没有定义, 就会执行View类中的dispatch方法
      5. dispatch方法中就是通过用户当前的请求的小写字符串进行反射. 当继承View的类中有get方法, 根据对象属性查找顺序就会调用子类中定义的get方法

    六、drf中的APIView源码阅读

    • 代码分析

      1. 切入点: urls.py中的.as_view()方法

        url(r'^booksapiview/', views.BooksAPIView.as_view()),
        
      2. 视图中BooksAPIView类

        class BooksAPIView(APIView):
            def get(self, request):
                # request 已经不是原生django的request了,是drf自己定义的request对象
                # print(request._request)
                # print(request.data)
                print(request.method)
                print(request.query_params)  # get请求,地址中的参数
                print(request.GET)
                return HttpResponse('ok')
        
            def post(self, request):
                print(request.data)  # urlencoded方式有数据,json格式也有,formdata也有数据
                print(type(request.POST))  # 原生的POST
                print(request._request.POST)
        
                return HttpResponse('ok')
        
      3. 项目启动时执行

        @classmethod 
        def as_view(cls, **initkwargs):
            ···
            view = super().as_view(**initkwargs) # 调用父类的as_view方法
            view.cls = cls # cls就是BooksAPIView
            return csrf_exempt(view) # 整个网站就取消的csrf的验证
        
      4. 执行APIView父类(View)的as_view方法,返回父类的view方法

        @classonlymethod
        def as_view(cls, **initkwargs):
            ···
            def view(request, *args, **kwargs):
                ···
                return self.dispatch(request, *args, **kwargs)
            return view
        
      5. 执行父类的view方法,并且调用dispatch方法,但是APIView自己写了一个dispatch方法,所以不会执行父类的dispatch方法

        # APIView的dispatch方法
            def dispatch(self, request, *args, **kwargs):
                self.args = args
                self.kwargs = kwargs
                # 重新包装成一个request对象,以后再用的request对象,就是新的request对象了
                request = self.initialize_request(request, *args, **kwargs)
                self.request = request
                self.headers = self.default_response_headers  # deprecate?
                try:
                    # 三大认证模块
                    self.initial(request, *args, **kwargs)
                    # Get the appropriate handler method
                    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)
                # 渲染模块
                self.response = self.finalize_response(request, response, *args, **kwargs)
                return self.response
        
      6. APIView自己封装的request对象方法initialize_request()方法

        def dispatch(self, request, *args, **kwargs):
        	···
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request # 已不再是django原来的request对象了
        
            
        def initialize_request(self, request, *args, **kwargs):
            parser_context = self.get_parser_context(request)
            return Request(
                request,
                parsers=self.get_parsers(),
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
        
      7. APIView自己的认证方法initial()方法

        def dispatch(self, request, *args, **kwargs):
            ···
            try:
                    # 三大认证模块
                self.initial(request, *args, **kwargs)
                # 和view里面的dispatch中的使用反射代码一致
                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:
                ···
        
        # APIView的initial方法
        def initial(self, request, *args, **kwargs):
            # 认证组件:校验用户 - 游客、合法用户、非法用户
            # 游客:代表校验通过,直接进入下一步校验(权限校验)
            # 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
            # 非法用户:代表校验失败,抛出异常,返回403权限异常结果
            self.perform_authentication(request)
            # 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
            # 认证通过:可以进入下一步校验(频率认证)
            # 认证失败:抛出异常,返回403权限异常结果
            self.check_permissions(request)
            # 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
            # 没有达到限次:正常访问接口
            # 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
            self.check_throttles(request)
        
      8. 继承APIView视图的类中含有的方法分析:

        • django drf
          request _request
          FILES FILES
          GET query_params
        • drf中的data对标django中的request,但是django中的request只能接收urlencoded和form-data格式的数据,drf中的data能接收urlencoded、form-data和json格式的数据

        from rest_framework.request import Request
        # 只要继承了APIView,视图类中的request对象,都是新的,也就是上面那个request的对象了
        # 老的request在新的request._request
        # 以后使用reqeust对象,就像使用之前的request是一模一样(因为重写了__getattr__方法)
          def __getattr__(self, attr):
                try:
                    return getattr(self._request, attr) #通过反射,取原生的request对象,取出属性或方法
                except AttributeError:
                    return self.__getattribute__(attr)
        
         # request.data 感觉是个数据属性,其实是个方法,@property,修饰了
        	它是一个字典,post请求不管使用什么编码,传过来的数据,都在request.data
         #get请求传过来数据,从哪取?
        	request.GET
            @property
            def query_params(self):
                """
                More semantically correct name for request.GET.
                """
                return self._request.GET
            
            #视图类中
             print(request.query_params)  #get请求,地址中的参数
             # 原来在
             print(request.GET)
        
    • 图示分析

      1. 切入点: urls.py中的.as_view()方法

        image-20201227211143295

      2. 视图中BooksAPIView类

        image-20201227211211468

      3. 项目启动时执行

        image-20201227211718502

      4. 执行APIView父类(View)的as_view方法,返回父类的view方法

        image-20201227212237716

      5. 执行父类的view方法,并且调用dispatch方法,但是APIView自己写了一个dispatch方法,所以不会执行父类的dispatch方法

        image-20201227212204787

      6. APIView自己封装的request对象方法initialize_request()方法

        image-20201227212408525

      7. APIView自己的认证方法initial()方法

        image-20201227212700980

      8. 继承APIView视图的类中含有的方法分析:

        • data,原装的request == _request

          image-20201227213015905

        • query_params,原装的GET == _request.GET

          image-20201227213134927

        • FILES

          image-20201227213255068

    七、拓展

    • 一切皆对象,函数也是对象

      def foo(a, b):
          return a + b
      foo.name = 'lqz'  # 由于一切皆对象,函数也是个对象,对象放值
      
      print(foo(2, 3))
      
      print(foo.name)  # lqz
      
    • 局部禁用csrf方法和csrf_exempt

      # 提示: 在视图函数上加装饰器@csrf_exempt. 与csrf_exempt(view)这么写和在视图函数上加装饰器是一模一样的.
      
      # urls.py中这种写法本质就是返回的views.test, 只是在原来基础之上不修改的调用方式, 以及原代码的情况下, 去除了csrf认证
      path('test/', csrf_exempt(views.test)),
      
  • 相关阅读:
    How to Create a site at the specified URL and new database (CommandLine Operation)
    Using Wppackager to Package and Deploy Web Parts for Microsoft SharePoint Products and Technologies
    SQL Server Monitor v0.5 [Free tool]
    How to build Web Part
    Deploy web part in a virtual server by developing a Web Part Package file(.cab)
    How to recreate "sites" link if you delete it accidentally
    SharePoint Portal Server管理匿名访问设置
    Monitor sql connection from .Net SqlClient Data Provider
    Brief installation instruction of Sharepoint Portal Server
    How to Use SharePoint Alternate URL Access
  • 原文地址:https://www.cnblogs.com/borntodie/p/14330720.html
Copyright © 2011-2022 走看看