zoukankan      html  css  js  c++  java
  • 五、django rest_framework源码之版本控制剖析

    1 绪论

      Djangorest_framework的版本控制允许用户更改不同客户端之间的行为,且提供了许多不同的版本控制方案。版本控制由传入的客户端请求确定,可以基于请求URL,也可以基于请求标头。

    版本控制入口在在dispatch方法中调用的initial方法中,如下所示:

    def initial(self, request, *args, **kwargs):
    
        ……
    
        #版本控制
    
        version, scheme = self.determine_version(request, *args, **kwargs)
    
        #将获得的版本号和版本类对象放入request中
    
        request.version, request.versioning_scheme = version, scheme
    
    
    
        self.perform_authentication(request)#认证
    
        self.check_permissions(request)#权限
    
        self.check_throttles(request)#频率控制

      可以看出,版本控制而是认证、权限、频率控制等操作之前。这一篇,我们来分析一下django rest_framework的版本控制源码。

    2 源码分析

      先来看看determine_version方法,源码如下:

    def determine_version(self, request, *args, **kwargs):
    
        if self.versioning_class is None:#读取配置好的版本控制类,如果没有配置就返回(None, None)
    
            return (None, None)
    
        scheme = self.versioning_class()#实例化版本控制类对象
    
        #调用封装在版本控制类中的determine_version方法
    
        #返回:(版本号 , 版本控制实例对象)
    
    return (scheme.determine_version(request, *args, **kwargs), scheme)

      获得版本号的关键在return语句中调用的determine_version方法中,我们以django rest_framework自带的版本控制类QueryParameterVersioning中的determine_version为例进行分析:

        

    def determine_version(self, request, *args, **kwargs):
    
            #获得request传入的版本号version_param , 项目配置的默认版本号default_version
    
            version = request.query_params.get(self.version_param, self.default_version)
    
            if not self.is_allowed_version(version):#如果不是允许的版本号则抛出异常
    
                raise exceptions.NotFound(self.invalid_version_message)
    
            return version

      判断是否是允许的版本,是在is_allowed_version方法中进行,具体是怎么一个过程呢?如下所示:   

    def is_allowed_version(self, version):
    
            #allowed_versions是BaseVersioning类中的属性,读取项目配置的允许的版本号,是一个列表
    
            # allowed_versions = api_settings.ALLOWED_VERSIONS
    
            if not self.allowed_versions:#如果没有设置允许版本号,则默认允许所有版本
    
                return True
    
            return (
    
                #如果request中的版本号不为空,且等于默认版本号
    
                    (version is not None and version == self.default_version)
    
                    or
    
                    (version in self.allowed_versions))#或者request的版本号在允许的版本号列表中

    is_allowed_version返回的是布尔型值,如果允许则返回True,如果拒绝则返回False。回到上面的determine_version方法中,如果is_allowed_version返回的是True,即是允许的版本号,那么版本控制对象中的determine_version方法就会继续向上返回request中的版本号,最初的initial方法调用的determine_version方法(两个determine_version可不一样)获得版本号之后会返回一个包含版本号和版本控制实例的元组,最后在initial方法中将版本号和版本实例信息添加到request中,整个版本控制过程就结束了。

    3 几种版本控制的方式

      Django rest_framework提供了4种版本控制方法,分别是:基于url的get传参方式获取版本(QueryParameterVersioning)、基于url的正则方式(URLPathVersioning)、基于 accept 请求头方式(AcceptHeaderVersioning)、基于主机名方法(HostNameVersioning),分别对应rest_framework。

    (注:本部分内容来源于听风。的博客https://www.cnblogs.com/huchong/p/8450355.html,感谢博主)

    3. 1 基于url的get传参方式获取版本

      如:/users?version=v1

      版本配置:

    REST_FRAMEWORK = {
    
        'DEFAULT_VERSION': 'v1',            # 默认版本
    
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
    
        'VERSION_PARAM': 'version'          # URL中获取值的key
    
    }

      路由配置:

    from django.conf.urls import url, include
    
    from web.views import TestView
    
     
    
    urlpatterns = [
    
        url(r'^test/', TestView.as_view(),name='test'),
    
    ]
    
    from rest_framework.views import APIView
    
    from rest_framework.response import Response
    
    from rest_framework.versioning import QueryParameterVersioning
    
    class TestView(APIView):
    
        versioning_class = QueryParameterVersioning
    
        def get(self, request, *args, **kwargs):
    
            # 获取版本
    
            print(request.version)
    
            # 获取版本管理的类
    
            print(request.versioning_scheme)
    
            # 反向生成URL
    
            reverse_url = request.versioning_scheme.reverse('test', request=request)
    
            print(reverse_url)
    
     
    
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
    
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
    
            return Response('PUT请求,响应内容')

    3.2 基于url的正则方式

      如:/v1/users/

      版本配置:

    REST_FRAMEWORK = {
    
        'DEFAULT_VERSION': 'v1',            # 默认版本
    
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
    
        'VERSION_PARAM': 'version'          # URL中获取值的key
    
    }

      路由配置:

    from django.conf.urls import url, include
    
    from web.views import TestView
    
    urlpatterns = [
    
        url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
    
    ]

      视图类:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import URLPathVersioning
    class TestView(APIView):
        versioning_class = URLPathVersioning
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
            return Response('GET请求,响应内容')
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')

    3.3 基于 accept 请求头方式

      如:Accept: application/json; version=1.0

      版本配置:

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }

      路由配置:

    from django.conf.urls import url, include
    from web.views import TestView
     
    urlpatterns = [
        url(r'^test/', TestView.as_view(), name='test'),
    ]

      视图:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import AcceptHeaderVersioning
    class TestView(APIView):
        versioning_class = AcceptHeaderVersioning
        def get(self, request, *args, **kwargs):
            # 获取版本 HTTP_ACCEPT头
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
            return Response('GET请求,响应内容')
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')

    3.4 基于主机名方法

      如:v1.example.com  

      版本配置:

    ALLOWED_HOSTS = ['*']
    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',  # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
        'VERSION_PARAM': 'version'  # URL中获取值的key
    }

      路由配置:

    from django.conf.urls import url, include
    from web.views import TestView
    urlpatterns = [
        url(r'^test/', TestView.as_view(), name='test'),
    ]

      视图:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import HostNameVersioning
     class TestView(APIView):
        versioning_class = HostNameVersioning
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
            return Response('GET请求,响应内容')
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')

      上面用的所有方法都是局部配置,如果是全局配置,是在项目的settings.py文件中配置:

    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
        'DEFAULT_VERSION': 'v1',
        'ALLOWED_VERSIONS': ['v1', 'v2'],
        'VERSION_PARAM': 'version' 
    }
  • 相关阅读:
    Java day03第三课流程控制
    java day02第二课基本数据类型、修饰符、运算符
    Objective-C 枚举类型和字符串互转方案
    UISlider
    ios中AES和RSA 加密
    1. SEL和IMP(动态性)
    《iOS开发进阶》
    【旧事重提】iOS中文件读写
    Apple移动设备处理器指令集 armv6、armv7、armv7s及arm64
    Unity3D 与 Xcode的结合
  • 原文地址:https://www.cnblogs.com/chenhuabin/p/9987467.html
Copyright © 2011-2022 走看看