首先,請求到達REST framework
的CBV,執行CBV中的dispatch
方法再次封裝完成request後,執行initial
方法.django
在REST framework
中的版本控制就是在initial
函數中調用determine_version
方法完成的api
來看看源碼瀏覽器
initial
方法的源碼:app
def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method handler. """ self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use. version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)
determine_version
方法的源碼函數
def determine_version(self, request, *args, **kwargs): if self.versioning_class is None: # 若是versioning_class爲空則返回一個None的元組 return (None, None) scheme = self.versioning_class() return (scheme.determine_version(request, *args, **kwargs), scheme)
determine_version
方法中的versioning_class
方法又是從哪裏來的呢測試
在UserView視圖函數中沒有定義versioning_class,那就要到UserView的父類APIView中去找url
在APIView類中定義了versioning_class的信息spa
class APIView(View): renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES parser_classes = api_settings.DEFAULT_PARSER_CLASSES authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS metadata_class = api_settings.DEFAULT_METADATA_CLASS versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
在視圖函數中打印versioning_class版本控制
None
能夠看到默認設置的versioning_class的值是None
,這說明咱們能夠在視圖函數中爲versioning_class設置一個值
rest
在detemine_version
函數的源碼中,能夠看到versioning_class後面加了一個括號,因此versioning_class是一個函數或一個類
若是versioning_class是一個函數,那麼執行versioning_class後會有一個返回值 若是versioning_class是一個類,那麼versioning_class加括號就實例化一個類
從rest_framework中導入versioning模塊
from rest_framework import versioning
而後進入versioning模塊,能夠看到這個versioning中定義了6個類
這6個類是BaseVersioning
,AcceptHeaderVersioning
,URLPathVersioning
,NamespaceVersioning
,HostNameVersioning
,QueryParameterVersioning
並且還能夠看到BaseVersioning類
是其他5個類的父類.
而且這其他的5個類,每一個類中都有一個determine_version
方法
在項目的視圖函數中導入其中任意一個類,打印versioning_class
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from django.views import View from rest_framework.versioning import QueryParameterVersioning class UsersView(APIView): versioning_class=QueryParameterVersioning def get(self,request,*args,**kwargs): print(self.versioning_class) #打印versioning_class return HttpResponse("aaaa")
打印結果
<class 'rest_framework.versioning.QueryParameterVersioning'>
因此versioning_class是一個類,而且versioning_class類中有一個determine_version方法
在initial
方法中,執行完determine_version
後的返回值被賦值給version, scheme這兩個變量
def initial(self, request, *args, **kwargs): self.format_kwarg = self.get_format_suffix(**kwargs) neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)
這兩個變量又把determine_version
方法的返回值賦值給request.version
, request.versioning_scheme
這兩個變量
在視圖函數中打印這兩個變量
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.versioning import QueryParameterVersioning class UsersView(APIView): versioning_class=QueryParameterVersioning def get(self,request,*args,**kwargs): print(self.versioning_class) print("request.version:",request.version) print("request.versioning_scheme:",request.versioning_scheme) return HttpResponse("aaaa")
打印結果
<class 'rest_framework.versioning.QueryParameterVersioning'> request.version: None request.versioning_scheme: <rest_framework.versioning.QueryParameterVersioning object at 0x00000000057722B0>
在上面的流程分析中,versioning模塊中定義了6個類
這6個類是BaseVersioning
,AcceptHeaderVersioning
,URLPathVersioning
,NamespaceVersioning
,HostNameVersioning
,QueryParameterVersioning
BaseVersioning類
是其他5個類的父類,REST framework
獲取版本調用的就是這5個類
在settings.py文件的INSTALLED_APPS
配置項中引入rest-framework
INSTALLED_APPS = [ ... 'rest_framework', ]
配置路由表
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/$',views.UsersView.as_view()), ]
視圖函數配置獲取版本方式爲QueryParameterVersioning
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.versioning import QueryParameterVersioning class UsersView(APIView): versioning_class=QueryParameterVersioning def get(self,request,*args,**kwargs): # print("request:",request.__dict__) print("request.version:",request.version) # 打印版本 # print(request.version.scheme) # print(request.versioning_scheme.reverse("test1",request=request)) # print(request.versioning_scheme.reverse(viewname="test1",request=request)) return HttpResponse("aaaa")
在瀏覽器中輸入http://127.0.0.1:8000/users/?version=v1
地址,服務端打印結果
request.version: v1
再把瀏覽器中的url地址更換爲http://127.0.0.1:8000/users/?version=v5
,刷新瀏覽器,服務端打印結果
request.version: v5
配置url路由信息
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^(?P<version>\w+)/users/$',views.UsersView.as_view()), ]
視圖函數配置獲取版本方式爲URLPathVersioning
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.versioning import URLPathVersioning class UsersView(APIView): versioning_class=URLPathVersioning def get(self,request,*args,**kwargs): print("request.version:",request.version) # 打印版本 return HttpResponse("aaaa")
在瀏覽器中輸入http://127.0.0.1:8000/v1/users/
地址,服務端打印結果
request.version: v1
再把瀏覽器中的url地址更換爲http://127.0.0.1:8000/v10/users/
,刷新瀏覽器,服務端打印結果
request.version: v10
在settings.py文件中添加以下配置
REST_FRAMEWORK = { 'VERSION_PARAM': "version", # 版本的參數,在url中能夠體現 'DEFAULT_VERSION': 'V1', # 默認的版本 'ALLOWED_VERSIONS': ['v1', 'v2','v3'] # 容許的版本 }
urls.py設定爲
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/$',views.UsersView.as_view()), ]
視圖函數定義
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.versioning import AcceptHeaderVersioning class UsersView(APIView): versioning_class=AcceptHeaderVersioning def get(self,request,*args,**kwargs): print("request.version:",request.version) # 獲取版本信息 return HttpResponse("aaaa")
用瀏覽器打開http://127.0.0.1:8000/users/
的url地址
request.version: V1 因爲在settings.py文件中已經設定了默認的版本是v1,因此在服務端後臺獲取到的版本是v1
把settings.py中定義的默認版本更改變v2或者v3,再次刷新瀏覽器,後臺打印的版本信息又會跟着改變
request.version: V2
urls.py設定爲
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^v1/users/',([url(r'test/',views.UsersView.as_view(),name='test1')],None,'v1')), url(r'^v2/users/',([url(r'test/',views.UsersView.as_view(),name='test2')],None,'v2')), ]
視圖函數定義
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.versioning import NamespaceVersioning class UsersView(APIView): versioning_class=NamespaceVersioning def get(self,request,*args,**kwargs): print("request.version:",request.version) # 獲取版本信息 return HttpResponse("aaaa")
用瀏覽器打開http://127.0.0.1:8000/v1/users/test/
的url地址
request.version: V1
把url的地址更換爲http://127.0.0.1:8000/v2/users/test/
,刷新瀏覽器,後臺打印信息以下
request.version: V2
在視圖函數中定義versioning_class
,只能做用於單個類,
若是想整個項目都使用同一種方法來進行版本控制,就能夠在settings.py文件中定義全局的versioning_class
在settings.py
中配置默認的versioning_class
爲URLPathVersioning
REST_FRAMEWORK={ 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning', }
在前面查看到BaseVersioning
的源碼時,能夠看到還有幾個參數能夠在settings.py文件中定義的
class BaseVersioning(object): default_version = api_settings.DEFAULT_VERSION allowed_versions = api_settings.ALLOWED_VERSIONS version_param = api_settings.VERSION_PARAM
再來看看這幾個參數配置項的做用
REST_FRAMEWORK={ # 默認使用URLPathVersioning類來獲取版本信息 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning', 'VERSION_PARAM':"version", # 版本的參數,在url中能夠體現 'DEFAULT_VERSION':'V1', # 默認的版本 'ALLOWED_VERSIONS':['v1','v2'] # 容許的版本 }
修改urls.py文件,使url能夠匹配任意長度的字符url
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^(?P<version>\w+)/users/$',views.UsersView.as_view()), ]
在瀏覽器中分別輸入http://127.0.0.1:8000/v1/users/
和http://127.0.0.1:8000/v2/users/
均可以獲取到正確的響應信息
再在瀏覽器中輸入http://127.0.0.1:8000/v3/users/
時,瀏覽器中出現了報錯
從這裏能夠知道,在settings.py文件中設定的url中容許的版本只能是v1或v2,在瀏覽器中輸入的版本是v3,因此就會出現錯誤了