restframework提供的版本模块
rest_framework.versioning
是内置版本模块,其他版本类要继承BaseVersioning
类
版本选择流程
在initial()方法中进行了认证、权限、限流验证之前有一段代码:
class APIView(View):
...
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS#django settings.py中定义会覆盖restframework settings.py
...
def determine_version(self, request, *args, **kwargs):
"""
If versioning is being used, then determine any API version for the
incoming request. Returns a two-tuple of (version, versioning_scheme)
"""
if self.versioning_class is None:
return (None, None)
scheme = self.versioning_class() #scheme在本例中是`URLPathVersioning类`的实例对象
return (scheme.determine_version(request, *args, **kwargs), scheme)#返回的元祖内容(版本字符串,版本类实例对象)
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
#确定API版本
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme#在业务views.py中,可以使用request.version获取版本号,request.versioning_scheme获取版本类的实例对象
# Ensure that the incoming request is permitted
self.perform_authentication(request) #认证
self.check_permissions(request) #权限
self.check_throttles(request) #限流
本例settings.py定义:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning'#这里不是list,是一个字符串
}
查看版本类URLPathVersioning源码:
class URLPathVersioning(BaseVersioning):
"""
To the client this is the same style as `NamespaceVersioning`.
The difference is in the backend - this implementation uses
Django's URL keyword arguments to determine the version.
An example URL conf for two views that accept two different versions.
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')
]
GET /1.0/something/ HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in URL path.')
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
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request.version is not None:
kwargs = {} if (kwargs is None) else kwargs
kwargs[self.version_param] = request.version
return super().reverse(
viewname, args, kwargs, request, format, **extra
)
代码注释中演示了url示例,django2.0之后正则url写法如下:
from django.urls import re_path
from user.views import OrderView
urlpatterns = [
re_path('(?P<version>[v1|v2]+)/order/', OrderView.as_view())
]
访问方式:http://localhost:8000/v1/order/,打印版本信息和版本类对象:
class OrderView(APIView):
def get(self,request,*args,**kwargs):
print(request.version)
print(request.versioning_scheme)
return HttpResponse("success")
>>>v1
>>><rest_framework.versioning.URLPathVersioning object at 0x0000000004FF1EB8>
返回版本类对象的作用是能够调用里面的reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra)
方法反向生成url,django和restframework反向url对比示例:
#urls.py
from django.urls import re_path
from user.views import OrderView
urlpatterns = [
re_path('(?P<version>[v1|v2]+)/order/', OrderView.as_view(),name="hello")
]
#views.py
class OrderView(APIView):
def get(self,request,*args,**kwargs):
django_reverse_url = reverse(viewname="hello",kwargs={"version":"v2"})
print(django_reverse_url)
restframework_reverse_url = request.versioning_scheme.reverse(viewname="hello",request=request)
print(restframework_reverse_url)
return HttpResponse("success")
>>>/v2/order/
>>>http://localhost:8000/v1/order/
查看URLPathVersioning
类中定义的reverse()
可以知道,restframework帮我们从request中取出version赋值,最后还是调用了django的reverse方法。
推荐使用URLPathVersioning
类做版本控制。
rest_framework.versioning
模块中还提供了其他类,比如QueryParameterVersioning
可以使用/something/?version=0.1
方式指定版本,具体可以查看源码中的注释。
全局配置
如果想让所有视图都必须要认证后才能访问,可以在django项目的settings.py中设置REST_FRAMEWORK
变量:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning'
}
局部配置
如果只是某个视图使用,可以在类中定义属性,比如:versioning_class= URLPathVersioning
网友评论