04 drf源码剖析之版本

04 drf源码剖析之版本

1. 版本简述

  • API版本控制使您可以更改不同客户端之间的行为。REST框架提供了许多不同的版本控制方案。

  • 版本控制由传入的客户端请求确定,并且可以基于请求URL或基于请求标头。

  • 启用API版本控制后,该request.version属性将包含一个字符串,该字符串与传入客户端请求中请求的版本相对应。

  • 默认情况下,版本控制未启用,并且request.version将始终返回None

2. 版本使用

  1. settings配置文件

    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
     'ALLOWED_VERSIONS':['v1','v2'],
        
    }
    
  2. 路由

    # 路由分发
    urlpatterns = [
        url(r'^api/(?P<version>\w+)/', include('api.urls')),
    ]
    
    # 子路由
    urlpatterns = [
        url(r'^order/$', views.OrderView.as_view()),
    ]
    
  3. 通过request.version可以取值

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    
    class OrderView(APIView):
        def get(self,request,*args,**kwargs):
            print(request.version)
            print(request.versioning_scheme)
            return Response('...')
    
        def post(self,request,*args,**kwargs):
            return Response('post')
    

3.源码剖析

  • 请求到来执行dispatch方法

    class APIView(View):
        versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
        
    	def dispatch(self, request, *args, **kwargs):
           
            # 第一步 
            self.args = args
            self.kwargs = kwargs
    
            """
            request = 生成了一个新的request对象,此对象的内部封装了一些值。
            request = Request(request)
                - 内部封装了 _request = 老的request
            """
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
    
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                # 第二步
                self.initial(request, *args, **kwargs)
    
                执行视图函数...
    
  • 执行initial方法

    def initial(self, request, *args, **kwargs):
           
        # 2.1 处理drf的版本
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme
    		...
    
  • determine_version

    • versioning_class是在配置文件设置的URLPathVersioning
    def determine_version(self, request, *args, **kwargs):
        if self.versioning_class is None:
            return (None, None)
        scheme = self.versioning_class() # obj = XXXXXXXXXXXX()
        return (scheme.determine_version(request, *args, **kwargs), scheme)
    
  • 接着去执行URLPathVersioning对象的determine_version方法

    class URLPathVersioning(BaseVersioning):
        """
        urlpatterns = [
            url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
           
        ]
        """
        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
    
    
    

4. 总结

  1. 请求过来执行dispatch方法中的initial方法中的版本处理的determine_version方法
  2. 找到setings配置中版本类URLPathVersioning,对其实例化,
  3. 执行实例化对象的determine_version方法,
  4. 该方法会获取路由中输入的版本信息,
  5. 在is_allowed_version方法中会判断url中的版本是否在settings配置设定的ALLOWED_VERSIONS列表中
  6. 如果在就将版本赋值给request.version,将版本类赋值给request.versioning_scheme
posted @ 2019-11-27 07:48  LBZHK  阅读(107)  评论(0编辑  收藏  举报