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)#频率控制
源码分析
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中,整个版本控制过程就结束了
版本控制方法
Django rest_framework提供了版本控制方法:基于url的get传参方式获取版本(QueryParameterVersioning)、基于url的正则方式(URLPathVersioning)和视图方法
get方式
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配置
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请求,响应内容’)
全局配置,是在项目的settings.py文件中配置
REST_FRAMEWORK = {
‘DEFAULT_VERSIONING_CLASS’:“rest_framework.versioning.URLPathVersioning”,
‘DEFAULT_VERSION’: ‘v1’,
‘ALLOWED_VERSIONS’: [‘v1’, ‘v2’],
‘VERSION_PARAM’: ‘version’
}