5、django rest_framework源碼之版本控制剖析

1 緒論

  Djangorest_framework的版本控制容許用戶更改不一樣客戶端之間的行爲,且提供了許多不一樣的版本控制方案。版本控制由傳入的客戶端請求肯定,能夠基於請求URL,也能夠基於請求標頭。html

版本控制入口在在dispatch方法中調用的initial方法中,以下所示:web

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的版本控制源碼。django

2 源碼分析

  先來看看determine_version方法,源碼以下:json

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爲例進行分析:api

    

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方法中進行,具體是怎麼一個過程呢?以下所示:   app

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。post

(注:本部份內容來源於聽風。的博客http://www.javashuo.com/article/p-qloxdckp-kk.html,感謝博主)url

3. 1 基於url的get傳參方式獲取版本

  如:/users?version=v1spa

  版本配置:

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' 
}
相關文章
相關標籤/搜索