点击查看代码
class APIView(View):
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?
        try:
            self.initial(request, *args, **kwargs)  
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            response = handler(request, *args, **kwargs)
        except Exception as exc:
            response = self.handle_exception(exc)
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    def initial(self, request, *args, **kwargs):
        self.format_kwarg = self.get_format_suffix(**kwargs)
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)
    def determine_version(self, request, *args, **kwargs):
# 优先到类APIView()中找versioning_class,没有再到全局配置中找
        if self.versioning_class is None: 
            return (None, None)
        scheme = self.versioning_class()
# 返回自定义版本类的对象中的determine_view()方法和类对象
        return (scheme.determine_version(request, *args, **kwargs), scheme)
 
点击查看代码
class HomeView(APIView):
    authentication_classes = []
    versioning_class = MyVersion
    def get(self, request):
        url = request.versioning_scheme.reverse('v1', request)
        return Response("这是版本{}的信息".format(request.version))
# 自定义版本类
class MyVersion(QueryParameterVersioning):
    def determine_version(self, request, *args, **kwargs):
        version = request.query_params.get('version')
        if not version:
            version = 'v1'
        return version
class QueryParameterVersioning(BaseVersioning):
    invalid_version_message = _('Invalid version in query parameter.')
    def determine_version(self, request, *args, **kwargs):
        version = request.query_params.get(self.version_param, self.default_version)
# 找父类的is_allowed_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):
        url = super().reverse(
            viewname, args, kwargs, request, format, **extra
        )
        if request.version is not None:
            return replace_query_param(url, self.version_param, request.version)
        return url
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 self.allowed_versions:
            return True
        return ((version is not None and version == self.default_version) or
                (version in self.allowed_versions))
def _reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
    if format is not None:
        kwargs = kwargs or {}
        kwargs['format'] = format
# 返回原生的django_reverse
    url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
    if request:
        return request.build_absolute_uri(url)
    return url