版本控制

准备

新建一个项目,采用路由分发的方式,采用之前的数据库表的例子并添加修改

目录结构如下:

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
# demoapimodels.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)
# demodemourls.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')),
]
# demoapiurls.py

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

urlpatterns = [
    url(r'^users/$', views.UsersView.as_view()),
]
# demoapiviews.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 访问

# demoapiviews.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 ,达到同样的效果

自定义版本组件

URL中通过GET传参

通过上面的 query_params ,可以自定义一个版本的组件,从而获取版本

# demoapiviews.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

还可以使用内置的方法去获取版本

# demoapiviews.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

可以在配置文件中设置默认的版本

# demodemosettings.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路径中传参(推荐使用)

它也是个内置的方法

# demoapiviews.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 中需要有所改动

# demoapiurls.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,这时推荐的使用方式

可以设置在配置文件中,做全局的设置,在视图函数中便可以省略

# demodemosettings.py

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

# demoapiviews.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
原文地址:https://www.cnblogs.com/qiuxirufeng/p/10458791.html