版本控制

準備

新建一個項目,採用路由分發的方式,採用以前的數據庫表的例子並添加修改python

目錄結構以下:sql

demo\
    api\
        migrations\
            __init__.py
        __init__.py
        admin.py
        apps.py
        models.py
        tests.py
        urls.py         # 路由分發後的urls
        views.py
    demo\
        __init__.py
        settings.py
        urls.py
        wsgi.py
    templates
    db.sqlite3
    manage.py
# demo\api\models.py

from django.db import models

class UserGroup(models.Model):
    title = models.CharField(max_length=32)

class UerInfo(models.Model):
    user_type_choices = (
        (1, '普通用戶'),
        (2, 'VIP'),
        (3, 'SVIP'),
    )
    user_type = models.IntegerField(choices=user_type_choices)
    username = models.CharField(max_length=32, unique=True)
    password = models.CharField(max_length=64)

    roles = models.ManyToManyField("Role")
    group = models.ForeignKey("UserGroup")

class UserToken(models.Model):
    user = models.OneToOneField(to='UerInfo')
    token = models.CharField(max_length=64)

class Role(models.Model):
    title = models.CharField(max_length=32)
# demo\demo\urls.py

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^api/', admin.site.urls),
    url(r'^api/', include('api.urls')),
]
# demo\api\urls.py

from django.conf.urls import url
from api import views

urlpatterns = [
    url(r'^users/$', views.UsersView.as_view()),
]
# demo\api\views.py

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

class UsersView(APIView):

    def get(self, request, *args, **kwargs):
        # 經過原生的request
        version = request._request.GET.get('version')
        print(version)
        return HttpResponse("用戶列表")

啓動項目,在瀏覽器輸入 http://127.0.0.1:8000/api/users/?version=v1 ,後臺會返回一個 v1,這是經過訪問原生的 request 去獲取版本數據庫

還有一種方法,經過 query_params 訪問django

# demo\api\views.py

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

class UsersView(APIView):

    def get(self, request, *args, **kwargs):
        version = request.query_params.get('version')
        print(version)
        return HttpResponse("用戶列表")

由於這是 query_params 內部本身訪問原生的 request ,達到一樣的效果json

自定義版本組件

URL中經過GET傳參

經過上面的 query_params ,能夠自定義一個版本的組件,從而獲取版本api

# demo\api\views.py

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

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

class UsersView(APIView):
    versioning_class = ParamVersion
    
    def get(self, request, *args, **kwargs):
        print(request.version)
        return HttpResponse("用戶列表")

啓動項目,在瀏覽器輸入 http://127.0.0.1:8000/api/users/?version=v2 ,後臺會返回一個 v2瀏覽器

還能夠使用內置的方法去獲取版本app

# demo\api\views.py

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import QueryParameterVersioning

class UsersView(APIView):

    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):
        print(request.version)
        return HttpResponse("用戶列表")
# 進入 QueryParameterVersioning 查看

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)
        # is_allowed_version是容許的版本
        if not self.is_allowed_version(version):
            raise exceptions.NotFound(self.invalid_version_message)
        return version
    
    # 反向生成URL
    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

能夠在配置文件中設置默認的版本函數

# demo\demo\settings.py

# 在末尾添加
REST_FRAMEWORK = {
    "DEFAULT_VERSION": 'v1',    # 默認版本
    "ALLOWED_VERSION": ['v1', 'v2'],    # 容許使用的版本
    "VERSION_PARAM": 'version'  # url中的key值
}

如今在瀏覽器中,只能經過訪問 http://127.0.0.1:8000/api/users/http://127.0.0.1:8000/api/users/?version=v1http://127.0.0.1:8000/api/users/?version=v2 的方式從後臺獲取數據url

URL路徑中傳參(推薦使用)

它也是個內置的方法

# demo\api\views.py

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import URLPathVersioning

class UsersView(APIView):

    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):
        print(request.version)
        return HttpResponse("用戶列表")

由於是經過路徑傳參,因此在 url 中須要有所改動

# demo\api\urls.py

from django.conf.urls import url
from api import views

urlpatterns = [
    url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view()),
]

這時在瀏覽器中經過 http://127.0.0.1:8000/api/v1/users/ 也能夠在後臺獲取 v1,這時推薦的使用方式

能夠設置在配置文件中,作全局的設置,在視圖函數中即可以省略

# demo\demo\settings.py

REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    "DEFAULT_VERSION": 'v1',
    "ALLOWED_VERSION": ['v1', 'v2'],
    "VERSION_PARAM": 'version'
}
# demo\api\views.py

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

class UsersView(APIView):
    def get(self, request, *args, **kwargs):
        print(request.version)
        return HttpResponse("用戶列表")

源碼流程

請求進來,先走 dispatch ,對 request 進行封裝,走 initial

def initial(self, request, *args, **kwargs):
    
    ... # 省略的內容
    
    # Determine the API version, if versioning is in use.
    version, scheme = self.determine_version(request, *args, **kwargs)
    request.version, request.versioning_scheme = version, scheme

    # Ensure that the incoming request is permitted
    # 認證、權限、頻率
    self.perform_authentication(request)
    self.check_permissions(request)
    self.check_throttles(request)
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)
    # 處理版本類的對象,就是 settings.py中 URLPathVersioning類的對象
    scheme = self.versioning_class()
    # 返回兩個值,第一個是調用determine_version的方法,根據請求獲取版本
    # 第二個scheme是處理版本的對象
    return (scheme.determine_version(request, *args, **kwargs), scheme)
class APIView(View):
    ... # 省略的內容
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

先處理版本再走認證、權限、頻率

反向生成URL

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from django.urls import reverse

class UsersView(APIView):

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

        # 1. 獲取版本
        print(request.version)
        # 2. 獲取版本處理的對象
        print(request.versioning_scheme)
        
        # 反向自動生成URL(你在瀏覽器訪問的url會給你打印出來)
        u1 = request.versioning_scheme.reverse(viewname='uu', request=request)
        print(u1)
        
        # 手動生成
        u2 = reverse(viewname='uu', kwargs={'version':2})
        print(u2)

        return HttpResponse("用戶列表")

總結

使用

配置文件

REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    "DEFAULT_VERSION":'v1',
    "ALLOWED_VERSIONS":['v1','v2'],
    "VERSION_PARAM":'version',
}

路由系統

urlpatterns = [
    url(r'^api/', admin.site.urls),
    url(r'^api/', include('api.urls')),
]

urlpatterns = [
    url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(), name='uu'),
]

視圖

  • 獲取版本
  • 獲取版本處理的對象
  • 反向生成URL
相關文章
相關標籤/搜索