流程:
- 執行self.initial(request, *args, **kwargs) 方法
- 擷取版本version, scheme = self.determine_version(request, *args, **kwargs)
settings 檔案全局配置:
'DEFAULT_VERSION': 'v1', #預設版本号
'VERSION_PARAM': 'version', #指定參數
'ALLOWED_VERSIONS': ['v1', 'v2'], #允許通路的版本号
自定義:
class Myversion(BaseVersioning):
def determine_version(self, request, *args, **kwargs):
# version = request._request.GET.get("version")
version = request.query_params.get("version")
return (version, ) # scheme 版本對象
# determine_version傳回後,設定到version, versioning_scheme
# version, scheme = self.determine_version(request, *args, **kwargs)
# request.version, request.versioning_scheme = version, scheme指派
# request.query_params(封裝方法) == request._request.GET
class Myview(APIView):
versioning_class = Myversion #指定版本擷取類
def get(self, request, *args, **kwargs):
print(request.version) #直接擷取值
print(request.versioning_scheme)
return Response("ok")
内置方法:
- QueryParameterVersioning 查詢字元串方式
def determine_version(self, request, *args, **kwargs):
version = request.query_params.get(self.version_param, self.default_version)
# version_param 為settings中的 VERSION_PARAM
# default_version 為settings中的 DEFAULT_VERSION
# is_allowed_version 判斷是否在 ALLOWED_VERSIONS清單中
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
- URLPathVersioning通過路由變量方式
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
]
def determine_version(self, request, *args, **kwargs):
version = kwargs.get(self.version_param, self.default_version) #通過傳遞的變量擷取
if version is None:
version = self.default_version
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
- HostNameVersioning 通過子域名的方式
"""
GET /something/ HTTP/1.1
Host: v1.example.com
Accept: application/json
"""
hostname_regex = re.compile(r'^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$')
invalid_version_message = _('Invalid version in hostname.')
def determine_version(self, request, *args, **kwargs):
hostname, separator, port = request.get_host().partition(':')
match = self.hostname_regex.match(hostname)
if not match:
return self.default_version
version = match.group(1) #擷取版本号
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
- 其它NamespaceVersioning(基于路由系統分發) , AcceptHeaderVersioning(基于Accept請求頭)
對于内置的rest_framework reverse函數:
print(request.versioning_scheme.reverse(viewname='Myview',request=request)) #反向生成url
#不用指定版本号是因為:重寫的reverse函數已經把版本号指派給kwargs:
# if request.version is not None:
# kwargs = {} if (kwargs is None) else kwargs
# kwargs[self.version_param] = request.version
print(reverse(viewname='Myview', kwargs={'version': 'v2'})) #原生的reverse函數 需指定版本号
'''
output:
http://127.0.0.1:8000/v1/Myview/
/v2/Myview/
'''