06 Django REST Framework 版本控制

 01-版本控制

對接口進行版本控制只是一種殺死已部署客戶端的「禮貌」方式。
- 羅伊菲爾丁。

1. API版本控制容許您更改不一樣客戶端之間的行爲。REST框架提供了許多不一樣的版本控制方案。

2. 版本控制由傳入的客戶端請求肯定,能夠基於請求URL,也能夠基於請求標頭。

3. 有許多有效的方法來處理版本控制。非版本化系統也是合適的,特別是若是您正在爲具備多個客戶端的長期系統進行工程設計。

02-版本控制方案

詳解:https://www.django-rest-framework.org/api-guide/versioning/django

03-版本控制的使用

3.1 全局配置

這裏咱們以 URLPathVersioning 爲例,仍是在項目的settings.py中REST_FRAMEWORK配置項下配置:json

REST_FRAMEWORK = {
    ...
    # 去url路徑裏面獲取版本
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'DEFAULT_VERSION': 'v1',              # 默認的版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],  # 容許的版本
    'VERSION_PARAM': 'version',  # 版本的參數名與URL conf中一致
}

urls.pyapi

urlpatterns = [
    ...
    url(r'^(?P<version>[v1|v2]+)/publishers/$', views.PublisherViewSet.as_view({'get': 'list', 'post': 'create'})),
    url(r'^(?P<version>[v1|v2]+)/publishers/(?P<pk>\d+)/$', views.PublisherViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),

]

咱們能夠在視圖中自定義具體的行爲,下面以不一樣的版本返回不一樣的序列化類爲例:瀏覽器

class PublisherViewSet(ModelViewSet):

    queryset = models.Publisher.objects.all()

    def get_serializer_class(self):
        """不一樣的版本使用不一樣的序列化類"""
        # request.version:獲取版本
        if self.request.version == 'v1':
            return PublisherModelSerializerVersion1
        else:
            return PublisherModelSerializer

3.2 局部配置

注意,一般咱們是不會單獨給某個視圖設置版本控制的,若是你確實須要給單獨的視圖設置版本控制,你能夠在視圖中設置versioning_class屬性,以下:app

class PublisherViewSet(ModelViewSet):

    ...
    versioning_class = URLPathVersioning

04-反向解析url

# api/urls.py

from django.urls import path,re_path
from .views import UserView

urlpatterns = [
    re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(),name = 'api_user'),
]
# api/views.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request

class UserView(APIView):

    def get(self,request,*args,**kwargs):
        #獲取版本
        print(request.version)
        #獲取處理版本的對象
        print(request.versioning_scheme)
        #獲取瀏覽器訪問的url,reverse反向解析
        #須要兩個參數:viewname就是url中的別名,request=request是url中要傳入的參數
        #(?P<version>[v1|v2]+)/users/,這裏原本須要傳version的參數,可是version包含在request裏面(源碼裏面能夠看到),全部只須要request=request就能夠
        url_path = request.versioning_scheme.reverse(viewname='api_user',request=request)
        print(url_path)
        # self.dispatch
        return HttpResponse('用戶列表')

05-versioning_class

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

url配置案例:框架

6.1 determine_version

裏面有個is_allowed_version,點進去能夠看到一些基本參數 (繼承BaseVersioning基類)ide

class BaseVersioning(object):
    #默認的版本
    default_version = api_settings.DEFAULT_VERSION
    #容許的版本
    allowed_versions = api_settings.ALLOWED_VERSIONS
    #默認參數(是version,好比你能夠自定義爲v)
    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))
相關文章
相關標籤/搜索