• 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指向配置文件。
        '''
    

    image-20220407203606146

    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)})
    

    image-20220407211241476

    此种方式使用较少,因为版本号通常是写在路由中而不是以参数的形式进行传播。

    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
            )
    

    内置类封装的功能已经可以满足大多数功能。

    全局配置:

    image-20220407214230372

    默认版本号,允许的版本号,版本参数名称。

    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/
    }
    

    image-20220407214953729

    继续努力,终成大器!

  • 相关阅读:
    S4全球总决赛(2)南邮NOJ2059
    S4全球总决赛(2)南邮NOJ2059
    S4全球总决赛(1) 南邮NOJ
    S4全球总决赛(1) 南邮NOJ
    S4全球总决赛(1) 南邮NOJ
    【Linux】鸟哥的Linux私房菜基础学习篇整理(五)
    【Linux】鸟哥的Linux私房菜基础学习篇整理(四)
    【HDOJ】2428 Stars
    【Linux】鸟哥的Linux私房菜基础学习篇整理(三)
    【Linux】鸟哥的Linux私房菜基础学习篇整理(二)
  • 原文地址:https://www.cnblogs.com/Blogwj123/p/16114467.html
Copyright © 2020-2023  润新知