码迷,mamicode.com
首页 > 其他好文 > 详细

五、django rest_framework源码之版本控制剖析

时间:2018-11-20 11:28:15      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:类对象   strong   clu   客户端   post   分析   mes   exce   ini   

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,感谢博主)

  • 基于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请求,响应内容)

 

  • 基于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请求,响应内容)
  • 基于 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请求,响应内容)
  • 基于主机名方法

  如: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 
}

 

五、django rest_framework源码之版本控制剖析

标签:类对象   strong   clu   客户端   post   分析   mes   exce   ini   

原文地址:https://www.cnblogs.com/chenhuabin/p/9987467.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!