美文网首页
版本源码流程

版本源码流程

作者: 小吉头 | 来源:发表于2020-07-21 11:48 被阅读0次

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

相关文章

网友评论

      本文标题:版本源码流程

      本文链接:https://www.haomeiwen.com/subject/hcjpcktx.html