版本控制
from rest_framework.versioning import QueryParameterVersioning
class user(APIView):
versioning_class = QueryParameterVersioning
def get(self,request):
# print(request.META)
return Response({'coed':123})
class QueryParameterVersioning(BaseVersioning):
"""
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in query parameter.')
def determine_version(self, request, *args, **kwargs):
#request.query_params.get会去url中读取self.version_param,如果没设置,就会读取默认的default_version,url中没有传递参数的话version=self.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
class BaseVersioning:
default_version = api_settings.DEFAULT_VERSION #设置默认的版本
allowed_versions = api_settings.ALLOWED_VERSIONS #可以设置允许的版本
version_param = api_settings.VERSION_PARAM #可以自己设置url中版本的键
修改读取版本信息的全局设置
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER':None,
#读取版本的时候会读取version这个键的值
'VERSION_PARAM':'version'
#如果没有传递版本信息,默认是v1
'DEFAULT_VERSION':'v1'
#允许的版本
'ALLOWED_VERSIONS':['v1','v2','v3']
}
源码解读
在dispatch中的initial:
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
## 1 ##通过self.determine_version获取version,此时会在QueryParameterVersioning
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)
def determine_version(self, request, *args, **kwargs):
## 2 ##获取我们定义的versioning_class并实例化,执行determine_version方法获取版本并返回
if self.versioning_class is None:
return (None, None)
scheme = self.versioning_class()
#注意这里是返回的第一个是版本,第二个返回值是版本的对象
return (scheme.determine_version(request, *args, **kwargs), scheme)
class QueryParameterVersioning(BaseVersioning):
"""
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in query parameter.')
#用于提取url中的版本的值
def determine_version(self, request, *args, **kwargs):
version = request.query_params.get(self.version_param, self.default_version)
#判断请求的版本是否合法,is_allowed_version方法在父类中
if not self.is_allowed_version(version):
#不合法就触发异常,会被dispatch捕获,因为是dispatch调用的inital
raise exceptions.NotFound(self.invalid_version_message)
return version
#反向生成url
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
#调用父类的reverse
url = super().reverse(
viewname, args, kwargs, request, format, **extra
)
#判断请求的版本是否合法
if request.version is not None:
return replace_query_param(url, self.version_param, request.version)
return url
class BaseVersioning:
default_version = api_settings.DEFAULT_VERSION
allowed_versions = api_settings.ALLOWED_VERSIONS
version_param = api_settings.VERSION_PARAM
def is_allowed_version(self, version):
if not self.allowed_versions:
return True
return ((version is not None and version == self.default_version) or
(version in self.allowed_versions))
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
#调用_reverse
return _reverse(viewname, args, kwargs, request, format, **extra)
def _reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
"""
Same as `django.urls.reverse`, but optionally takes a request
and returns a fully qualified URL, using the request to get the base URL.
"""
if format is not None:
kwargs = kwargs or {}
kwargs['format'] = format
#实际上是调用django的reverse
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
if request:
return request.build_absolute_uri(url)
return url
请求不合法的版本
'''GET /user/?version=v4'''
HTTP 404 Not Found
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"detail": "Invalid version in query parameter."
}
反向生成url
'''
urlpatterns = [
# path("admin/", admin.site.urls),
path("user/", views.user.as_view(),name='na'),
]
'''
url = request.versioning_scheme.reverse('na',request=request)
print('反向生成url:',url)
--反向生成url: http://127.0.0.1:8000/user/?version=v3
版本参数传递方法2:放在url中
path("api/<str:version>/index", views.index.as_view(), name='no'),
#请求的url: http://127.0.0.1:8000/api/v1/index
#views.py
from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning
class index(APIView):
versioning_class = URLPathVersioning
def get(self,request,*args,**kwargs):
url = request.versioning_scheme.reverse('no',request=request)
print(url)
return Response({'asd':123})
版本参数传递方法3:在请求头中
#请求的键和值 Accept: application/json; version=v1
class headversion(APIView):
versioning_class = AcceptHeaderVersioning
def get(self,request):
url = request.versioning_scheme.reverse('ne',request=request)
print(url)
return Response({'asd':12})
设置全局读取版本路径
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER':None,
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v1',
'ALLOWED_VERSIONS':['v1','v2','v3'],
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning'
}