• DRF介绍,DRF项目开发,DRF项目的视图类的dispatch源码解析


    一、DRF介绍

    1. 什么是DRF

    • DRF就是django框架的一个插件或者说是django的一个工具包,用于在Web后台构建Restful接口。

    2. 为什么要用DRF

    (1)使用DRF的原因

    • 总的来说:
      • 既然django有自带的CBV模型,为什么还要重新再学习一个DRF来搭建我们的项目呢。因为drf提供了更多的功能(如三大验证,Restful接口等),它的CBV模型比django自带的CBV模型更加好用,对大项目来说功能更完善,开发效率更高。
    • 细的来说:
      • 先从项目规模来看,如果是小项目(几个简单的接口和页面),用Django的FBV足矣,简单明了,学习成本低;中大型项目、多人参与的项目,建议使用DRF,虽然学习路线较长,但是长期来看,效率和规范性都更高
      • 我们重用DRF的另一个原因是项目分工的精细化,通过引入前端团队,将原来的模板直出的方式优化为前后台分离,页面渲染的数据都通过Restful接口来提供,前端工程化,后端服务化,代码解耦,开发效率更高

    (2)站在开发者的角度来说用DRF的好处(暂时列举这么多)

    1. 安装到Django工程中,你就能在Django中提供Restful接口了
    2. 你可以在一个Web页面上浏览自己提供了哪些API,并且可以通过这个页面测试这些API
    3. 你不用自己写一套接口鉴权代码了
    4. 你不用自己写大量的CRUD接口了,简单配置即可
    5. 你不用自己写大量的条件查询接口了,简单配置即可
    6. 你不用自己写后台分页逻辑了,简单配置即可
    7. 你不用自己写接口限流逻辑了,简单配置即可
    8. 你不用自己写各种简单的参数校验逻辑了,简单配置即可
    9. 你不用自己注册各种路由了,简单配置即可
    10. 你的权限控制逻辑不用写到业务逻辑中了

    二、用DRF开发后端项目

    • 就是下载安装drf之后,在我们新建的django项目中,注册drf,再书写符合restful接口规范的路由,在views文件中书写drf的CBV模型(drf使用的视图类都是继承APIView的类)。

    • 项目实例:

    '''
    drf框架安装:
        1)drf是Django的插件,所以要提前按照Django框架
        2)终端中使用命令:python pip install djangorestframework
        3)使用drf时,要在settings中注册
    '''
    # settings文件中:
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    
        # drf一定需要注册
        'rest_framework',
    	# 应用程序注册
        'api',
    ]
    
    
    # urls文件中:
    
    from django.conf.urls import url
    from . import views
    
    urlpatterns = [
        # url(r'^v1/books/$', views.BookView.as_view()),
        # url(r'^v1/books/(?P<pk>d+)/$', views.BookView.as_view()),
        #
        # url(r'^v2/books/$', views.BookAPIView.as_view()),
        # url(r'^v2/books/(?P<pk>d+)/$', views.BookAPIView.as_view()),
    
        url(r'^books/$', views.BookAPIView.as_view()),
        url(r'^books/(?P<pk>d+)/$', views.BookAPIView.as_view()),
    ]
    
    # views文件中:
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
    from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
    from rest_framework import status
    
    class BookAPIView(APIView):
        # 局部配置解析类:只适用当前视图类
        parser_classes = [JSONParser, FormParser, MultiPartParser]
        # 局部配置渲染类:只适用当前视图类
        renderer_classes = [JSONRenderer, BrowsableAPIRenderer]
    
        def get(self, request, *args, **kwargs):
            # a
            response = Response(
                data={
                    'msg': 'apiview get ok'
                },
                status=status.HTTP_404_NOT_FOUND,
            )
            print(response.data)
            return response
        def post(self, request, *args, **kwargs):
            print(request._request.method)  # 在内部将wsgi的request赋值给request._request
            print(request.method)  # 就是通过__getattr__走的是request._request.method
            print(request.query_params)  # 走的是方法属性,就是给request._request.GET重新命名
            print(request.data)  # 走的是方法属性,值依赖于request._full_data
    
            return Response({
                'msg': 'apiview post ok'
            })
    

    三、APIView请求生命周期

    • APIView是drf的视图类继承的类,就是drf提供的类
    # APIView请求生命周期
    
    '''
    APIView的as_view(局部禁用csrf校验) => 
    走父级的as_view调用dispatch分发请求 => 
    APIView自己重写了dispatch,使用自己完成分发 => 
    分发前完成request二次封装、数据解析 => 
    三大认证 => 
    请求的实际响应(自己的视图类的处理分发) => 
    出现了异常,就会交给异常模块处理异常 => 
    响应模块完成响应、渲染模块可以json或浏览器两种方式渲染
    '''
    

    四、源码的dispatch中的方法

    • 源码的dispatch作用是对不同请求方式的分发到对应的类的方法,最后将响应结果返回给前端。
    • 源码的dispatch就相当于是视图层的入口。其内部包含很多业务逻辑

    1. dispatch中的功能模块

    (1)请求模块

    '''
    drf源码的dispatch中对wsgi的request进行了二次封装:
    
        用新的request._request = wsgi的request
    
        用新的request.query_params = wsgi的request.GET
    
        用新的request.data = request._full_data    _full_data里利用解析模块获取的是wsgi的request.POST 和 request.body 和异常信息 等数据
    
        在外部访问新的request.属性,源码中通过在__getattr__方法中的利用反射,访问新的request.属性会先去wsgi的request中查找,若没有,再去新的request中找
        
    '''
    

    (2)解析模块

    • 配置允许解析的数据格式类型,并最后把解析的数据都赋值给新的request.data
    # 局部配置:(在需要配置的视图类中定义,只对当前配置的视图类有作用)
    parser_classes = [JSONParser, FormParser, MultiPartParser]
    
    # 全局配置:(在settings文件中配置,对全部视图类都有作用)
    
    REST_FRAMEWORK = {
        # 全局配置解析类:适用于所有视图类
        'DEFAULT_PARSER_CLASSES': [
            # 'rest_framework.parsers.JSONParser',
            # 'rest_framework.parsers.FormParser',
            # 'rest_framework.parsers.MultiPartParser'
        ],
        # 全局配置渲染类:适用于所有视图类
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            # 'rest_framework.renderers.BrowsableAPIRenderer',  # 上线后尽量关闭
        ],
        # 异常模块:异常处理函数
        # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
        'EXCEPTION_HANDLER': 'api.exception.exception_handler',  # api.exception中api是app名,exception是我们新建的异常模块文件名
    }
    	
    

    (3)响应模块

    Respose(data=常量|列表|字典, status=网络状态码)
    
    # 网络状态码的数字是后端自定义的,但是数字对应的状态信息是http协议规定好了的,不能修改,当网络状态码到前端中,其状态信息会自动展示出来。
    

    (4)渲染模块

    • 配置客户端得到响应数据后的渲染方式
    # 局部配置:(在需要配置的视图类中定义,只对当前配置的视图类有作用)
    renderer_classes = [JSONRenderer, BrowsableAPIRenderer]  # 在实际开发者,不需要 BrowsableAPIRenderer 参数,因为这个参数会让浏览器显示一个页面,其包含了当前项目的信息。我们只需要用JSONRenderer让前端只展示数据即可
    
    
    # 全局配置:(在settings文件中配置,对全部视图类都有作用)
    REST_FRAMEWORK = {
        # 全局配置解析类:适用于所有视图类
        'DEFAULT_PARSER_CLASSES': [
            # 'rest_framework.parsers.JSONParser',
            # 'rest_framework.parsers.FormParser',
            # 'rest_framework.parsers.MultiPartParser'
        ],
        # 全局配置渲染类:适用于所有视图类
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            # 'rest_framework.renderers.BrowsableAPIRenderer',  # 上线后尽量关闭
        ],
        # 异常模块:异常处理函数
        # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
        'EXCEPTION_HANDLER': 'api.exception.exception_handler',  # api.exception中api是app名,exception是我们新建的异常模块文件名
    }
    

    (5)异常模块

    • DRF自带的异常模块,只会捕捉前端的异常,后端的异常需要我们自己捕捉,所以我们需要自己重写异常模块,为原来的异常模块添加捕捉后端异常的功能。

    • 重写异常模块,分两步

    
    # 1. settings中配置全局异常模块:*********************************************
    
    REST_FRAMEWORK = {
        # 全局配置解析类:适用于所有视图类
        'DEFAULT_PARSER_CLASSES': [
            # 'rest_framework.parsers.JSONParser',
            # 'rest_framework.parsers.FormParser',
            # 'rest_framework.parsers.MultiPartParser'
        ],
        # 全局配置渲染类:适用于所有视图类
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            # 'rest_framework.renderers.BrowsableAPIRenderer',  # 上线后尽量关闭
        ],
        # 异常模块:异常处理函数
        # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
        'EXCEPTION_HANDLER': 'api.exception.exception_handler',  # api.exception中api是app名,exception是我们新建的异常模块文件名
    }
    
    # 2. 在app文件夹中新建一个py文件,重写exception_handler方法*********************************************
    
    # 一定要在settings文件中将异常模块配置成自己的异常处理函数
    from rest_framework.views import exception_handler as drf_exception_handler
    from rest_framework.response import Response
    
    # 先交给drf处理客户端异常,如果结果response为None代表服务器异常,自己处理
    # 最终一定要在日志文件中记录异常现象
    def exception_handler(exc, context):  # 重写异常模块exception_handler
        response = drf_exception_handler(exc, context)  # 利用原模块继续捕捉前端异常
        detail = '%s - %s - %s' % (context.get('view'), context.get('request').method, exc)
        if not response:  # 服务端错误
            response =  Response({'detail': detail})
        else:
            response.data = {'detail': detail}
        
        # 在终端打印报错信息
        import sys  
        sys.stderr.write('异常:%s
    ' % response.data.get('detail'))
    
        # 核心:要将response.data.get('detail')信息记录到日志文件
        # logger.waring(response.data.get('detail'))
    
        return response
    
  • 相关阅读:
    Oracle 字符集的查看和修改
    Hibernate查询方法与缓存的关系
    Oracle Sql语句整理
    Android动画效果
    Acrobat9键盘快捷键
    Head区的设置
    JAR,WAR,EAR区别
    ASCII码表完整版
    HTML的meta标签详解
    .NET中TextBox控件设置ReadOnly=true后台取不到值三种解决方法
  • 原文地址:https://www.cnblogs.com/Mcoming/p/12093446.html
Copyright © 2020-2023  润新知