Django Rest framework 之 版本
Django Rest framework 之 版本
- RESTful 規範
- django rest framework 之 認證(一)
- django rest framework 之 許可權(二)
- django rest framework 之 節流(三)
- django rest framework 之 版本(四)
- django rest framework 之 解析器(五)
- django rest framework 之 序列化(六)
- django rest framework 之 分頁(七)
- django rest framework 之 檢視(八)
轉載於蔚藍的藍的部落格
一、前言
1、版本的重要性
在RESTful 規範中,有關版本的問題,用restful規範做開放介面的時候,使用者請求API,系統返回資料。但是難免在系統發展的過程中,不可避免的需要新增新的資源,或者修改現有資源。因此,改動升級必不可少,但是,作為平臺開發者,應該知道:一旦你的API開放出去,有人開始用了,平臺的任何改動都需要考慮對當前使用者的影響。因此,做開放平臺,從第一個API的設計就需要開始API的版本控制策略問題,API的版本控制策略就像是開放平臺和平臺使用者之間的長期協議,其設計的好壞將直接決定使用者是否使用該平臺,或者說使用者在使用之後是否會因為某次版本升級直接棄用該平臺。
2、定義版本
怎麼定義版本協議,前端後端怎麼協調。有以下幾種方式:
- 請求頭中定義
GET /something/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0 #版本為1.0
- URL中定義
URL: example.com/v1.0/ # 版本為1.0
GET /1.0/something/ HTTP/1.1
Host: example.com
Accept: application/json
- 子域名中定義
GET /something/ HTTP/1.1 Host: v1.example.com # 版本為1.0 Accept: application/json
- HttpReqeust引數傳遞
GET /something/?version=0.1 HTTP/1.1 # 版本為1.0
Host: example.com
Accept: application/json
二、示例
在django rest framewrok
中,如果沒有在配置檔案setting.py
中設定預設的VERSION_PARAM
,即版本引數,drf
會設定預設的引數為version
,並將獲取到的version
的值封裝到request.version
中
1、請求頭中定義
django rest framework
的request
其實是對原生的Django
的HttpRequest
做了一個封裝,通過直接獲取屬性可以獲取到請求頭中的版本號
django rest framework的request
原生的Django
的HttpRequest
請求頭的版本和其他請求頭資訊最終會放到META
中,因此想要獲取版本號可以如下這樣
version = request._request.META.get('version') # 獲取版本號
2、子域名中定義
同樣的像請求頭中定義一樣,在請求頭中也可以直接獲取的域名,放到META中,因此想要獲取版本號可以如下這樣
host = request._request.META.get('HTTP_HOST') # 先獲取主機域名
version = host.split('.')[0] # 獲取版本號
注:其實在django rest framework
內部也有關於以上兩種定義版本的處理方法
3、HttpReqeust引數傳遞
之前分別在django rest framework中關於節流,認證,許可權三個元件,這裡新建一個Django
專案,命名為drf2。並進入當前目錄下執行python manage.py startapp api
,將新建的app,和rest_framework
放入INSTALLED_APPS。
# setting.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'api'
]
<1>、目錄結構
<2>、路由系統
from django.conf.urls import url
from .views import VersionView
urlpatterns = [
url(r'^version/$', VersionView.as_view()),
]
<3>、檢視
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.versioning import QueryParameterVersioning
class VersionView(APIView):
versioning_class = QueryParameterVersioning # 區域性配置請求引數處理
def get(self, request, *args, **kwargs):
version = request.version
ret = {
'code': 1000,
'msg': '請求成功',
‘version': version
}
return JsonResponse(ret)
<4>、配置檔案
像之前在許可權,節流那樣,可以配置一個全域性預設的版本解析類
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning", # 預設是url處理版本
"DEFAULT_VERSION":'v1', # 預設版本
"ALLOWED_VERSIONS":['v1','v2'], # 允許版本
"VERSION_PARAM":'version', # 版本引數例如 ?version=v1,,則表示版本為v1
}
<5>、測試
使用postman或者瀏覽器傳送請求測試
提供正常版本號:http://127.0.0.1:8000/api/version/?version=v1
獲取版本成功
傳送錯誤版本號:http://127.0.0.1:8000/api/version/?version=v3
由於允許版本只有v1和v2,所以版本錯誤,返回錯誤資訊
不提供版本號:假如在url請求中不新增引數,http://127.0.0.1:8000/api/version/?
,能獲取到預設的版本號
4、URL中定義
在url中定義,例如http://127.0.0.1:8000/api/v1/
<1>、路由系統
from django.conf.urls import url
from .views import VersionView
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/$', VersionView.as_view()), # 可用版本為v1和v2
]
<2>、檢視
from django.http import JsonResponse
from django.http import HttpRequest
from rest_framework.views import APIView, Request
from rest_framework.versioning import URLPathVersioning
class VersionView(APIView):
versioning_class = URLPathVersioning # 區域性配置版本類
def get(self, request, *args, **kwargs):
version = request.version
ret = {
'code': 1000,
'msg': '請求成功',
'version': version
}
return JsonResponse(ret)
或者也可以全域性配置, 不過使用URL解析的時候,需要在路由系統中正則匹配設定可用的版本,
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
"VERSION_PARAM":'version', # 引數
}
<3>、測試
使用postman或者瀏覽器傳送請求測試
http://127.0.0.1:8000/api/v1/
,正確的獲取版本號
5、反向解析URL
在django中也提供了一個url解析的函式reverse
,不過在django rest framework
中也有一個將reverse
函式封裝一層的介面可以進行url反向解析。
路由系統:加入namespace引數
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url
urlpatterns = [
url(r'^api/', include('api.urls', namespace='api') ),
]
子路由系統:加入name引數
from django.conf.urls import url
from .views import VersionView
app_name = 'api'
urlpatterns = [
url(r'^version/$', VersionView.as_view(), name='version'),
url(r'^(?P<version>[v1|v2]+)/$', VersionView.as_view(), name='version'),
]
示例一:引數攜帶版本
http://127.0.0.1:8000/api/version/?version=v1
,傳送請求
class VersionView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
version = request.version
url1 = request.versioning_scheme.reverse(viewname='api:version', request=request)
url2 = reverse(viewname='api:version', kwargs=kwargs)
ret = {
'code': 1000,
'msg': '請求成功',
'version': version,
'drf_url': url1,
'django_url': url2
}
return JsonResponse(ret)
使用postman返送請求
示例二:URL攜帶版本
http://127.0.0.1:8000/api/v1/
,傳送請求
class VersionView(APIView):
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
version = request.version
url1 = request.versioning_scheme.reverse(viewname='api:version', request=request)
url2 = reverse(viewname='api:version', kwargs=kwargs)
ret = {
'code': 1000,
'msg': '請求成功',
'version': version,
'drf_url': url1,
'django_url': url2
}
return JsonResponse(ret)
使用postman返送請求
這裡有與drf的reverse
在對django中的reverse
函式進行封裝的時候,獲取了request.get_full_url()
,並做了一個拼接,所以才會出現全部的url
三、原始碼分析
1、找到initial()方法
依舊從dispath
方法進入原始碼,找到initial
方法
2、進入initial()方法
這裡呼叫了determine_version()
方法,並拿到兩個返回值並封裝到request中。這時候request.version_scheme
就是一個版本物件了
3、檢視具體的determine_version()方法
4、預設的版本處理物件
可以在setting.py
中配置之後,全域性使用
5、drf提供的版本類
在url反向解析中,呼叫了request.versioning_scheme.reverse()
中的reverse()
方法,說明request.versioning_scheme
返回的是一個版本物件,可以呼叫他的方法
BaseVersioning基類定義了三個介面
- determine_version:返回版本
- reverse:url反向解析使用
- is_allowed_version:就是判斷版本號是否合法
而上面示例使用的兩個超類URLPathVersioning,QueryParameterVersioning
其實也就是,重寫了determine_version,和reverse
兩個方法。
四、總結
版本的獲取方式有多種,在django rest framewok
中也提供了一一對應的處理版本物件,可以根據自己的需要配置,或者繼承重寫介面使用。
配置也支援全域性配置,和區域性配置,在全域性配置的時候,需要定義預設的版本號,以防萬一。
在進行url反向解析的時候django rest framewok
提供了一個更好的方式。