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
先来看看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中,整个版本控制过程就结束了。源码分析
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
如:/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请求,响应内容')
如:/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请求,响应内容')
如: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请求,响应内容')
如: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' }