Django Rest framework 之 版本
- RESTful 规范
 - django rest framework 之 认证(一)
 - django rest framework 之 权限(二)
 - django rest framework 之 节流(三)
 - django rest framework 之 版本(四)
 - django rest framework 之 解析器(五)
 - django rest framework 之 序列化(六)
 - django rest framework 之 分页(七)
 - django rest framework 之 视图(八)
 
一、前言
1、版本的重要性
在RESTful 规范中,有关版本的问题,用restful规范做开放接口的时候,用户请求API,系统返回数据。但是难免在系统发展的过程中,不可避免的需要添加新的资源,或者修改现有资源。因此,改动升级必不可少,但是,作为平台开发者,应该知道:一旦你的API开放出去,有人开始用了,平台的任何改动都需要考虑对当前用户的影响。因此,做开放平台,从第一个API的设计就需要开始API的版本控制策略问题,API的版本控制策略就像是开放平台和平台用户之间的长期协议,其设计的好坏将直接决定用户是否使用该平台,或者说用户在使用之后是否会因为某次版本升级直接弃用该平台。
2、定义版本
怎么定义版本协议,前端后端怎么协调。有以下几种方式:
- 请求头中定义
 
    GET /something/ HTTP/1.1
    Host: example.com
    Accept: application/json; version=1.0  #版本为1.0
- URL中定义
 
    URL: example.com/v1.0/  # 版本为1.0
    GET /1.0/something/ HTTP/1.1
    Host: example.com
    Accept: application/json
- 子域名中定义
 
    GET /something/ HTTP/1.1
    Host: v1.example.com # 版本为1.0
    Accept: application/json
- HttpReqeust参数传递
 
    GET /something/?version=0.1 HTTP/1.1  # 版本为1.0
    Host: example.com
    Accept: application/json
二、示例
在django rest framewrok中,如果没有在配置文件setting.py中设置默认的VERSION_PARAM,即版本参数,drf会设置默认的参数为version,并将获取到的version的值封装到request.version中
1、请求头中定义
django rest framework的request其实是对原生的Django的HttpRequest做了一个封装,通过直接获取属性可以获取到请求头中的版本号
django rest framework的request

原生的Django的HttpRequest

请求头的版本和其他请求头信息最终会放到META中,因此想要获取版本号可以如下这样
version = request._request.META.get('version')  # 获取版本号
2、子域名中定义
同样的像请求头中定义一样,在请求头中也可以直接获取的域名,放到META中,因此想要获取版本号可以如下这样
host = request._request.META.get('HTTP_HOST')  # 先获取主机域名
version = host.split('.')[0]  #  获取版本号
注:其实在django rest framework内部也有关于以上两种定义版本的处理方法
3、HttpReqeust参数传递
之前分别在django rest framework中关于节流,认证,权限三个组件,这里新建一个Django项目,命名为drf2。并进入当前目录下执行python manage.py startapp api,将新建的app,和rest_framework放入INSTALLED_APPS。
# setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'api'
]
<1>、目录结构

<2>、路由系统
from django.conf.urls import url
from .views import VersionView
urlpatterns = [
    url(r'^version/$', VersionView.as_view()),
]
<3>、视图
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.versioning import  QueryParameterVersioning
class VersionView(APIView):
    versioning_class = QueryParameterVersioning  # 局部配置请求参数处理
    def get(self, request, *args, **kwargs):
        version = request.version
        ret = {
            'code': 1000,
            'msg': '请求成功',
            ‘version': version
        }
        return JsonResponse(ret)
<4>、配置文件
像之前在权限,节流那样,可以配置一个全局默认的版本解析类
REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",  # 默认是url处理版本
    "DEFAULT_VERSION":'v1',  # 默认版本
    "ALLOWED_VERSIONS":['v1','v2'],  # 允许版本
    "VERSION_PARAM":'version',  # 版本参数例如  ?version=v1,,则表示版本为v1
}
<5>、测试
使用postman或者浏览器发送请求测试
提供正常版本号:http://127.0.0.1:8000/api/version/?version=v1 获取版本成功

发送错误版本号:http://127.0.0.1:8000/api/version/?version=v3 由于允许版本只有v1和v2,所以版本错误,返回错误信息

不提供版本号:假如在url请求中不添加参数,http://127.0.0.1:8000/api/version/?,能获取到默认的版本号

4、URL中定义
在url中定义,例如http://127.0.0.1:8000/api/v1/
<1>、路由系统
from django.conf.urls import url
from .views import VersionView
urlpatterns = [
    url(r'^(?P<version>[v1|v2]+)/$', VersionView.as_view()),  # 可用版本为v1和v2
]
<2>、视图
from django.http import JsonResponse
from django.http import HttpRequest
from rest_framework.views import APIView, Request
from rest_framework.versioning import URLPathVersioning
class VersionView(APIView):
    versioning_class = URLPathVersioning  # 局部配置版本类
    def get(self, request, *args, **kwargs):
        version = request.version
        ret = {
            'code': 1000,
            'msg': '请求成功',
            'version': version
        }
        return JsonResponse(ret)
或者也可以全局配置, 不过使用URL解析的时候,需要在路由系统中正则匹配设置可用的版本,
REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    "VERSION_PARAM":'version',  # 参数
}
<3>、测试
使用postman或者浏览器发送请求测试
http://127.0.0.1:8000/api/v1/,正确的获取版本号

5、反向解析URL
在django中也提供了一个url解析的函数reverse,不过在django rest framework中也有一个将reverse函数封装一层的接口可以进行url反向解析。
路由系统:加入namespace参数
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url
urlpatterns = [
    url(r'^api/', include('api.urls', namespace='api') ),
]
子路由系统:加入name参数
from django.conf.urls import url
from .views import VersionView
app_name = 'api' 
urlpatterns = [
    url(r'^version/$', VersionView.as_view(), name='version'),
    url(r'^(?P<version>[v1|v2]+)/$', VersionView.as_view(), name='version'),
]
示例一:参数携带版本
http://127.0.0.1:8000/api/version/?version=v1,发送请求
class VersionView(APIView):
    versioning_class = QueryParameterVersioning
    def get(self, request, *args, **kwargs):
        version = request.version
        url1 = request.versioning_scheme.reverse(viewname='api:version', request=request)
        url2 = reverse(viewname='api:version', kwargs=kwargs) 
        ret = {
            'code': 1000,
            'msg': '请求成功',
            'version': version,
            'drf_url': url1,
            'django_url': url2
        }
        return JsonResponse(ret)
使用postman返送请求

示例二:URL携带版本
http://127.0.0.1:8000/api/v1/,发送请求
class VersionView(APIView):
    versioning_class = URLPathVersioning
    def get(self, request, *args, **kwargs):
        version = request.version
        url1 = request.versioning_scheme.reverse(viewname='api:version', request=request)
        url2 = reverse(viewname='api:version', kwargs=kwargs)
        ret = {
            'code': 1000,
            'msg': '请求成功',
            'version': version,
            'drf_url': url1,
            'django_url': url2
        }
        return JsonResponse(ret)
使用postman返送请求

这里有与drf的reverse在对django中的reverse函数进行封装的时候,获取了request.get_full_url(),并做了一个拼接,所以才会出现全部的url
三、源码分析
1、找到initial()方法
依旧从dispath方法进入源码,找到initial方法

2、进入initial()方法
这里调用了determine_version()方法,并拿到两个返回值并封装到request中。这时候request.version_scheme就是一个版本对象了

3、查看具体的determine_version()方法

4、默认的版本处理对象
可以在setting.py中配置之后,全局使用

5、drf提供的版本类
在url反向解析中,调用了request.versioning_scheme.reverse()中的reverse()方法,说明request.versioning_scheme返回的是一个版本对象,可以调用他的方法

BaseVersioning基类定义了三个接口
- determine_version:返回版本
 - reverse:url反向解析使用
 - is_allowed_version:就是判断版本号是否合法
 
而上面示例使用的两个超类URLPathVersioning,QueryParameterVersioning其实也就是,重写了determine_version,和reverse两个方法。
四、总结
版本的获取方式有多种,在django rest framewok中也提供了一一对应的处理版本对象,可以根据自己的需要配置,或者继承重写接口使用。
配置也支持全局配置,和局部配置,在全局配置的时候,需要定义默认的版本号,以防万一。
在进行url反向解析的时候django rest framewok提供了一个更好的方式。
Django Rest framework 之 版本的更多相关文章
- Django REST framework之版本,解释器,序列化
		
1 版本 2 解释器 3.序列化 1 版本 通过?后面传版本号有两种方法: 方法一 from django.shortcuts import render from rest_framework.vi ...
 - Django rest framework 之版本
		
一.通过 QueryParameterVersioning 获取版本 通过 QueryParameterVersioning 从 get 请求中获取版本信息: 1.新建 app,名为 api,Proj ...
 - Django Rest framework 之  序列化
		
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
 - Django Rest framework 之  解析器
		
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
 - Django Rest framework 之  节流
		
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
 - Django Rest framework 之  权限
		
django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) django res ...
 - Django Rest framework 之  认证
		
django rest framework 官网 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest fra ...
 - Django Rest framework 之 视图
		
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
 - Django Rest framework 之 分页
		
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
 
随机推荐
- Windows核心编程:第1章 错误处理
			
Github https://github.com/gongluck/Windows-Core-Program.git //第1章 错误处理.cpp: 定义应用程序的入口点. // #include ...
 - vs2008快捷键一览表
			
Ctrl+E,D ---- 格式化全部代码 Ctrl+K,F ---- 格式化选中的代码 CTRL + SHIFT + B 生成解决方 ...
 - mybatis 控制台打印sql语句
			
其实很简单,打印SQL只需要加一个setting就可以了.亲测可用. mybatis-config.xml: <settings> <setting name=&quo ...
 - python实现桶排序算法
			
桶排序算法也是一种可以以线性期望时间运行的算法,该算法的原理是将数组分到有限数量的桶里,每个桶再分别排序. 它的算法流程如下所示: 设置一个定量的数组当作空桶子. 寻访序列,并且把项目一个一个放到对应 ...
 - windows phone开发-windows azure mobile service使用入门
			
在使用azure之前,我一直只能做本地app,或者使用第三方提供的api,尽管大多数情况下够用,但是仍不能随心所欲操纵数据,这种感觉不是特别好.于是在azure发布后,我就尝试使用azure来做为个人 ...
 - 机器学习与Tensorflow(6)——LSTM的Tensorflow实现、Tensorboard简单实现、CNN应用
			
最近写的一些程序以及做的一个关于轴承故障诊断的程序 最近学习进度有些慢 而且马上假期 要去补习班 去赚下学期生活费 额.... 抓紧时间再多学习点 1.RNN递归神经网络Tensorflow实现程序 ...
 - F#周报2019年第17期
			
新闻 .NET版本的Apache Spark Apache Spark预览版介绍 F# Apache Spark示例 微软Build 2019大会(5月6日至8日) Rider用于F#的解决方案内的重 ...
 - epel安装第三方扩展源后,运行yum报错的解决方案
			
yum安装报错:Cannot retrieve metalink for repository: epel. Please verify its path and try again 解决方法: 一句 ...
 - [java初探09]__关于java的包装类
			
前言 在Java语言的学习过程中,我们逐渐的理解了Java面向对象的思想,与类和对象的应用.但是在基本数据类型的使用上,我们无法将其定义为一个对象,通过使用对象的方法来使用它们,但是Java语言的思想 ...
 - C#7.0--引用返回值和引用局部变量
			
一.在C#7.0以上版本中,方法的返回值可以通过关键字ref指定为返回变量的引用(而不是值)给调用方,这称为引用返回值(Reference Return Value,或ref returns): 1. ...