五、django rest_framework源码之版本控制剖析
1 绪论
Djangorest_framework的版本控制允许用户更改不同客户端之间的行为,且提供了许多不同的版本控制方案。版本控制由传入的客户端请求确定,可以基于请求URL,也可以基于请求标头。
版本控制入口在在dispatch方法中调用的initial方法中,如下所示:
def initial(self, request, *args, **kwargs):
……
#版本控制
version, scheme = self.determine_version(request, *args, **kwargs)
#将获得的版本号和版本类对象放入request中
request.version, request.versioning_scheme = version, scheme
self.perform_authentication(request)#认证
self.check_permissions(request)#权限
self.check_throttles(request)#频率控制
可以看出,版本控制而是认证、权限、频率控制等操作之前。这一篇,我们来分析一下django rest_framework的版本控制源码。
2 源码分析
先来看看determine_version方法,源码如下:
def determine_version(self, request, *args, **kwargs):
if self.versioning_class is None:#读取配置好的版本控制类,如果没有配置就返回(None, None)
return (None, None)
scheme = self.versioning_class()#实例化版本控制类对象
#调用封装在版本控制类中的determine_version方法
#返回:(版本号 , 版本控制实例对象)
return (scheme.determine_version(request, *args, **kwargs), scheme)
获得版本号的关键在return语句中调用的determine_version方法中,我们以django rest_framework自带的版本控制类QueryParameterVersioning中的determine_version为例进行分析:
def determine_version(self, request, *args, **kwargs):
#获得request传入的版本号version_param , 项目配置的默认版本号default_version
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
判断是否是允许的版本,是在is_allowed_version方法中进行,具体是怎么一个过程呢?如下所示:
def is_allowed_version(self, version):
#allowed_versions是BaseVersioning类中的属性,读取项目配置的允许的版本号,是一个列表
# allowed_versions = api_settings.ALLOWED_VERSIONS
if not self.allowed_versions:#如果没有设置允许版本号,则默认允许所有版本
return True
return (
#如果request中的版本号不为空,且等于默认版本号
(version is not None and version == self.default_version)
or
(version in self.allowed_versions))#或者request的版本号在允许的版本号列表中
is_allowed_version返回的是布尔型值,如果允许则返回True,如果拒绝则返回False。回到上面的determine_version方法中,如果is_allowed_version返回的是True,即是允许的版本号,那么版本控制对象中的determine_version方法就会继续向上返回request中的版本号,最初的initial方法调用的determine_version方法(两个determine_version可不一样)获得版本号之后会返回一个包含版本号和版本控制实例的元组,最后在initial方法中将版本号和版本实例信息添加到request中,整个版本控制过程就结束了。
3 几种版本控制的方式
Django rest_framework提供了4种版本控制方法,分别是:基于url的get传参方式获取版本(QueryParameterVersioning)、基于url的正则方式(URLPathVersioning)、基于 accept 请求头方式(AcceptHeaderVersioning)、基于主机名方法(HostNameVersioning),分别对应rest_framework。
(注:本部分内容来源于听风。的博客https://www.cnblogs.com/huchong/p/8450355.html,感谢博主)
3. 1 基于url的get传参方式获取版本
如:/users?version=v1
版本配置:
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
路由配置:
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(),name='test'),
]
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioning
class TestView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET请求,响应内容')
def post(self, request, *args, **kwargs):
return Response('POST请求,响应内容')
def put(self, request, *args, **kwargs):
return Response('PUT请求,响应内容')
3.2 基于url的正则方式
如:/v1/users/
版本配置:
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
路由配置:
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
]
视图类:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
class TestView(APIView):
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET请求,响应内容')
def post(self, request, *args, **kwargs):
return Response('POST请求,响应内容')
def put(self, request, *args, **kwargs):
return Response('PUT请求,响应内容')
3.3 基于 accept 请求头方式
如:Accept: application/json; version=1.0
版本配置:
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
路由配置:
from django.conf.urls import url, include
from web.views import TestView urlpatterns = [
url(r'^test/', TestView.as_view(), name='test'),
]
视图:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import AcceptHeaderVersioning
class TestView(APIView):
versioning_class = AcceptHeaderVersioning
def get(self, request, *args, **kwargs):
# 获取版本 HTTP_ACCEPT头
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET请求,响应内容')
def post(self, request, *args, **kwargs):
return Response('POST请求,响应内容')
def put(self, request, *args, **kwargs):
return Response('PUT请求,响应内容')
3.4 基于主机名方法
如:v1.example.com
版本配置:
ALLOWED_HOSTS = ['*']
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
路由配置:
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(), name='test'),
]
视图:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import HostNameVersioning
class TestView(APIView):
versioning_class = HostNameVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET请求,响应内容')
def post(self, request, *args, **kwargs):
return Response('POST请求,响应内容')
def put(self, request, *args, **kwargs):
return Response('PUT请求,响应内容')
上面用的所有方法都是局部配置,如果是全局配置,是在项目的settings.py文件中配置:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
'DEFAULT_VERSION': 'v1',
'ALLOWED_VERSIONS': ['v1', 'v2'],
'VERSION_PARAM': 'version'
}
五、django rest_framework源码之版本控制剖析的更多相关文章
- 四、django rest_framework源码之频率控制剖析
1 绪言 权限判定之后的下一个环节是访问频率控制,本篇我们分析访问频率控制部分源码. 2 源码分析 访问频率控制在dispatch方法中的initial方法调用check_throttles方法开始. ...
- 一、django rest_framework源码之总体流程剖析
1 序言 有如下django代码,视图层: from django.http import HttpResponse from rest_framework.views import APIView ...
- 二、django rest_framework源码之认证流程剖析
1 绪言 上一篇中讲了django rest_framework总体流程,整个流程中最关键的一步就是执行dispatch方法.在dispatch方法中,在调用了一个initial方法,所有的认证.权限 ...
- 六、django rest_framework源码之解析器剖析
1 绪论 网络传输数据只能传输字符串格式的,如果是列表.字典等数据类型,需要转换之后才能使用但是我们之前的rest_framework例子都没有转换就直接可以使用了,这是因为rest_framewor ...
- 三、django rest_framework源码之权限流程剖析
1 绪言 上一篇中分析了认证部分的源码,认证后的下一个环节就是权限判定了.事实上,权限判定肯定要与认证联合使用才行,因为认证部分不会对请求进行禁止或者是允许,而只是根据请求中用户信息进行用户身份判断, ...
- 七、django rest_framework源码之视图
1 绪言 当大家看大这篇博文的时候,应该对Django rest_framework中的CBV有所了解了,大致来说就是通过定义类来继承APIView类,并在类中定义get.post.put.delet ...
- Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块
目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax c ...
- Django session 源码流程
流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...
- django --- DetailView源码分析
[背景] 最近在看django官方文档的class-based-views这一节的时候一直不得要领,感觉自己清楚,但是回想起来又没有脉络:于是没有办法只 能是“暗中观察”django的源码了. 刚打开 ...
随机推荐
- C++利用cin输入时检测回车的方法
今天做TJU的OJ ,其中一道题是先读入一个字符串,再读入一个整数,循环往复,直到字符串是空,也就是说回车键结束循环. 但是cin对空格和回车都不敏感,都不影响继续读入数据,所以需要一种新的方式检测回 ...
- 定价(Price)
传送门 [题目描述] 在市场上有很多商品的定价类似于 999 元.4999 元.8999 元这样.它们和 1000 元.5000 元和 9000 元并没有什么本质区别,但是在心理学上会让人感觉便宜很多 ...
- win7.wifi热点
使用本地连接上网,将网卡设为wifi热点 cmd 管理员身份运行 netsh wlan set hostednetwork mode=allow ssid=4Gtest key=12345678 网络 ...
- Q - Phalanx
题目链接:https://vjudge.net/contest/68966#problem/Q 分析:这里的对称并不是指的是关于原矩阵(也就是最大的那一个)主对角线对称,而是对于每一个小的矩阵来说,当 ...
- [转]CNN目标检测(一):Faster RCNN详解
https://blog.csdn.net/a8039974/article/details/77592389 Faster RCNN github : https://github.com/rbgi ...
- PATH变量重复
命令: export PATH=$(echo $PATH | tr : "\n"| sort | uniq | tr "\n" :) Code: awk -F: ...
- 缓存数据库-redis数据类型和操作(sorted set)
一:Redis 有序集合(sorted set) Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员. 不同的是每个元素都会关联一个double类型的分数.redis正是 ...
- HTML语义化(2016/3/16更新)
目录 什么是HTML语义化? 为什么要语义化 常用标签的语义 HTML5新元素 一.什么是HTML语义化? 简单来讲就是:每个标签做自己的事,使得能够被机器直接读懂. 二.为什么要语义化? 1.更容易 ...
- java基础26 线程的通讯;wait()、notify()、notifyAll()等方法
线程的通讯:一个线程完成了自己的任务时,要通知另一个线程去完成另一个任务 1.1.方法 wait():等待.如果线程执行到了wait()方法,那么该线程会进入等待状态,等待状态下的线程必须要被其他线程 ...
- virtualenv,virtualenvwrapper安装及使用
1.安装 # 安装: (sudo) pip install virtualenv virtualenvwrapper # centos7下 pip install virtualenv virtual ...