django-rest-framework(六)(版本)

版本

版本号可以写在url当中;可以写在url的get方法当中;可以写在namespace当中;可以写在请求头当中;也可以写在子域名当中。通常情况下是将版本号写在url当中

自定义的版本控制

将版本放在url的get请求参数中
class UserView(APIView):

    def get(self, request, *args, **kwargs):
        # query_params  =  self._request.GET
        # 获取请求参数中的version
        version = request.query_params.get('version')
        print(version)
        return HttpResponse('用户列表')

局部类形式的版本控制

class MyVersion(object):
    def determine_version(self, request, *args, **kwargs):
        version = request.query_params.get('version')
        return version


class UserView(APIView):
    versioning_classes = [MyVersion, ]
    
    def get(self, request, *args, **kwargs):
        # query_params  =  self._request.GET
        version = request.query_params.get('version')
        print(version)
        return HttpResponse('用户列表')

django-rest-framework中内置的版本控制

class BaseVersioning(object):
    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))


class AcceptHeaderVersioning(BaseVersioning):
    """
    GET /something/ HTTP/1.1
    Host: example.com
    Accept: application/json; version=1.0
    """
    invalid_version_message = _('Invalid version in "Accept" header.')

    def determine_version(self, request, *args, **kwargs):
        media_type = _MediaType(request.accepted_media_type)
        version = media_type.params.get(self.version_param, self.default_version)
        version = unicode_http_header(version)
        if not self.is_allowed_version(version):
            raise exceptions.NotAcceptable(self.invalid_version_message)
        return version

    # We don't need to implement `reverse`, as the versioning is based
    # on the `Accept` header, not on the request URL.


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 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(URLPathVersioning, self).reverse(
            viewname, args, kwargs, request, format, **extra
        )


class NamespaceVersioning(BaseVersioning):
    """
    To the client this is the same style as `URLPathVersioning`.
    The difference is in the backend - this implementation uses
    Django's URL namespaces to determine the version.

    An example URL conf that is namespaced into two separate versions

    # users/urls.py
    urlpatterns = [
        url(r'^/users/$', users_list, name='users-list'),
        url(r'^/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
    ]

    # urls.py
    urlpatterns = [
        url(r'^v1/', include('users.urls', namespace='v1')),
        url(r'^v2/', include('users.urls', namespace='v2'))
    ]

    GET /1.0/something/ HTTP/1.1
    Host: example.com
    Accept: application/json
    """
    invalid_version_message = _('Invalid version in URL path. Does not match any version namespace.')

    def determine_version(self, request, *args, **kwargs):
        resolver_match = getattr(request, 'resolver_match', None)
        if resolver_match is None or not resolver_match.namespace:
            return self.default_version

        # Allow for possibly nested namespaces.
        possible_versions = resolver_match.namespace.split(':')
        for version in possible_versions:
            if self.is_allowed_version(version):
                return version
        raise exceptions.NotFound(self.invalid_version_message)

    def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
        if request.version is not None:
            viewname = self.get_versioned_viewname(viewname, request)
        return super(NamespaceVersioning, self).reverse(
            viewname, args, kwargs, request, format, **extra
        )

    def get_versioned_viewname(self, viewname, request):
        return request.version + ':' + viewname


class HostNameVersioning(BaseVersioning):
    """
    GET /something/ HTTP/1.1
    Host: v1.example.com
    Accept: application/json
    """
    hostname_regex = re.compile(r'^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$')
    invalid_version_message = _('Invalid version in hostname.')

    def determine_version(self, request, *args, **kwargs):
        hostname, separator, port = request.get_host().partition(':')
        match = self.hostname_regex.match(hostname)
        if not match:
            return self.default_version
        version = match.group(1)
        if not self.is_allowed_version(version):
            raise exceptions.NotFound(self.invalid_version_message)
        return version

    # We don't need to implement `reverse`, as the hostname will already be
    # preserved as part of the REST framework `reverse` implementation.


class QueryParameterVersioning(BaseVersioning):
    """
    GET /something/?version=0.1 HTTP/1.1
    Host: example.com
    Accept: application/json
    """
    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)
        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(QueryParameterVersioning, self).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

1、 通常情况下不继承BaseVersioning类,自定义版本控制
2、 继承QueryParameterVersioning类

  • url形式: GET /something/?version=0.1 HTTP/1.1
  • 视图函数
from rest_framework.versioning import QueryParameterVersioning

class UserView(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes = []
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):

        # 获取版本号
        print(request.version)

        return HttpResponse('用户列表')
  • setting中的配置
REST_FRAMEWORK = {
    # 版本控制
    'VERSION_PARAM': 'version', # 版本参数,即请求中的参数名
    'DEFAULT_VERSION': 'v1', # 默认的版本号
    'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许使用的版本号
}

3、继承URLPathVersioning类 (比较常用

  • url形式:GET /1.0/something/ HTTP/1.1
  • url的书写
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')
    ]
  • 视图函数
from rest_framework.versioning import URLPathVersioning

class UserView(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes = []
    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):

        # 获取版本号
        print(request.version)

        return HttpResponse('用户列表')
  • 全局设置
REST_FRAMEWORK = {
    # 版本控制
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'VERSION_PARAM': 'version', # 版本参数,即请求中的参数名
    'DEFAULT_VERSION': 'v1', # 默认的版本号
    'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许使用的版本号
}

4、继承NamespaceVersioning类

# users/urls.py
    urlpatterns = [
        url(r'^/users/$', users_list, name='users-list'),
        url(r'^/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
    ]

 # urls.py
    urlpatterns = [
        url(r'^v1/', include('users.urls', namespace='v1')),
        url(r'^v2/', include('users.urls', namespace='v2'))
    ]

url :GET /1.0/something/ HTTP/1.1

5、继承AcceptHeaderVersioning类
版本名放在请求头中

GET /something/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0

6、继承HostNameVersioning类
版本名放在子域名中

GET /something/ HTTP/1.1
Host: v1.example.com
Accept: application/json

版本控制的一些用法

class UserView(APIView):

    def get(self, request, *args, **kwargs):
        # 获取版本号
        print(request.version)

        # 获取处理版本的对象
        print(request.versioning_scheme)

        # 反向生成url
        ul = request.versioning_scheme.reverse(viewname='user', request=request)
        print(ul)
        
        return HttpResponse('用户列表')

猜你喜欢

转载自blog.csdn.net/qq_33458131/article/details/83686260