drf(五)—版本控制
drf(五)—版本控制
1.源码流程
与前几节的介绍相同源码入口依旧为dispatch()
和inital()
;
def initial(self, request, *args, **kwargs):
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.
version, scheme = self.determine_version(request, *args, **kwargs)
# 猜测可能是版本控制,进入查看。
# 将版本赋值给request对象。
request.version, request.versioning_scheme = version, scheme
# 因此,当我们想要获取版本的时候应该可以直接去request中进行查找
# Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
determine_version() 函数。
def determine_version(self, request, *args, **kwargs):
if self.versioning_class is None:
return (None, None)#版本控制类不存在,返回值为None
scheme = self.versioning_class() # 实例化版本控制类的对象。
return (scheme.determine_version(request, *args, **kwargs), scheme)
# 返回值是两个对象,一个是执行函数,另一个是控制类的实例化对象
'''
版本控制类中使用的不是列表生成式,表明版本控制类只有一个而不是多个。
此处表明版本控制类中需要具备determine_version()方法。
结合上面函数猜想,返回值应该是版本与对象.
versioning_class指向配置文件。
'''
2.自定义使用
class ParamVersion(object):
def determine_version(self, request, *args, **kwargs):
version = request.query_params.get('version')
return version
自定义的类中直接获取参数;
from app01.utils.version import ParamVersion
class VersionView(APIView):
throttle_classes = []
permission_classes = []
authentication_classes = [] #为方便验证直接将认证功能在该函数中取消。
versioning_class = ParamVersion #版本控制类不能使用列表,因此直接使用类名
def get(self,request,*args,**kwargs):
version=request.version
print(version)
return JsonResponse({"msg":"当前版本是%s"%(version)})
此种方式使用较少,因为版本号通常是写在路由中而不是以参数的形式进行传播。
3.内置版本控制类
from rest_framework.versioning import URLPathVersioning,BaseVersioning
BaseVersioning类
class BaseVersioning:
default_version = api_settings.DEFAULT_VERSION # 读取配置文件
allowed_versions = api_settings.ALLOWED_VERSIONS
version_param = api_settings.VERSION_PARAM
def determine_version(self, request, *args, **kwargs):
msg = '{cls}.determine_version() must be implemented.'
raise NotImplementedError(msg.format(
cls=self.__class__.__name__
))
# 表明该方法必须被重写
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
return _reverse(viewname, args, kwargs, request, format, **extra)
# 该方法可以进行路由解析
def is_allowed_version(self, version):
if not from rest_framework.versioning import URLPathVersioningself.allowed_versions:
return True
return ((version is not None and version == self.default_version) or
(version in self.allowed_versions))
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 = [
re_path(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
# 使用动态路由进行传参。
re_path(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
)
内置类封装的功能已经可以满足大多数功能。
全局配置:
默认版本号,允许的版本号,版本参数名称。
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":['app01.utils.auth.MyAuthentication',],
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,
"DEFAULT_PERMISSION_CLASSES":['app01.utils.permission.MyPermission',],
"DEFAULT_THROTTLE_CLASSES":['app01.utils.throttle.MyThrottle',],
# 匿名用户不能在全局配置需要为登录功能单独添加
"DEFAULT_THROTTLE_RATES":{
"visit":'3/m',#一分钟三次,匿名用户
"loginuser":'10/m',# 登录成功,一分钟10次
},
# 版本的配置直接配置即可使用内置的版本控制类。
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'], #允许的版本号
"VERSION_PARAM":"version",# 这个参数应该和 路由中的名称相同version/
}
继续努力,终成大器!