1.REST framework版本控制的流程分析

1.1 determine_version方法的执行流程

首先,请求到达REST framework的CBV,执行CBV中的dispatch方法再次封装完成request后,执行initial方法.

REST framework中的版本控制就是在initial函数中调用determine_version方法完成的

来看看源码

initial方法的源码:

def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # 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)

determine_version方法的源码

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

    if self.versioning_class is None:    # 如果versioning_class为空则返回一个None的元组
return (None, None)
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)

determine_version方法中的versioning_class方法又是从哪里来的呢

1.2 versioning_class的由来

在UserView视图函数中没有定义versioning_class,那就要到UserView的父类APIView中去找

在APIView类中定义了versioning_class的信息

class APIView(View):

	renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
metadata_class = api_settings.DEFAULT_METADATA_CLASS
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

在视图函数中打印versioning_class

None

可以看到默认设置的versioning_class的值是None,这说明我们可以在视图函数中为versioning_class设置一个值

detemine_version函数的源码中,可以看到versioning_class后面加了一个括号,所以versioning_class是一个函数或一个类

如果versioning_class是一个函数,那么执行versioning_class后会有一个返回值
如果versioning_class是一个类,那么versioning_class加括号就实例化一个类

从rest_framework中导入versioning模块

from rest_framework import versioning

然后进入versioning模块,可以看到这个versioning中定义了6个类

这6个类是BaseVersioning,AcceptHeaderVersioning,URLPathVersioning,NamespaceVersioning,HostNameVersioning,QueryParameterVersioning

而且还可以看到BaseVersioning类是其余5个类的父类.

并且这其余的5个类,每个类中都有一个determine_version方法

在项目的视图函数中导入其中任意一个类,打印versioning_class

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from django.views import View
from rest_framework.versioning import QueryParameterVersioning class UsersView(APIView):
versioning_class=QueryParameterVersioning def get(self,request,*args,**kwargs):
print(self.versioning_class) #打印versioning_class return HttpResponse("aaaa")

打印结果

<class 'rest_framework.versioning.QueryParameterVersioning'>

所以versioning_class是一个类,并且versioning_class类中有一个determine_version方法

1.3 REST framework版本控制的流程总结

initial方法中,执行完determine_version后的返回值被赋值给version, scheme这两个变量

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

    self.format_kwarg = self.get_format_suffix(**kwargs)

    neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)

这两个变量又把determine_version方法的返回值赋值给request.version, request.versioning_scheme这两个变量

在视图函数中打印这两个变量

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(self.versioning_class)
print("request.version:",request.version)
print("request.versioning_scheme:",request.versioning_scheme) return HttpResponse("aaaa")

打印结果

<class 'rest_framework.versioning.QueryParameterVersioning'>
request.version: None
request.versioning_scheme: <rest_framework.versioning.QueryParameterVersioning object at 0x00000000057722B0>

2. REST framework获取版本的方法

在上面的流程分析中,versioning模块中定义了6个类

这6个类是BaseVersioning,AcceptHeaderVersioning,URLPathVersioning,NamespaceVersioning,HostNameVersioning,QueryParameterVersioning

BaseVersioning类是其余5个类的父类,REST framework获取版本调用的就是这5个类

2.1 QueryParameterVersioning:基于url的get传参方式

在settings.py文件的INSTALLED_APPS配置项中引入rest-framework

INSTALLED_APPS = [
...
'rest_framework',
]

配置路由表

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^users/$',views.UsersView.as_view()),
]

视图函数配置获取版本方式为QueryParameterVersioning

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:",request.__dict__)
print("request.version:",request.version) # 打印版本
# print(request.version.scheme)
# print(request.versioning_scheme.reverse("test1",request=request))
# print(request.versioning_scheme.reverse(viewname="test1",request=request)) return HttpResponse("aaaa")

在浏览器中输入http://127.0.0.1:8000/users/?version=v1地址,服务端打印结果

request.version: v1

再把浏览器中的url地址更换为http://127.0.0.1:8000/users/?version=v5,刷新浏览器,服务端打印结果

request.version: v5

2.2 URLPathVersioning:基于url的正则方式

配置url路由信息

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^(?P<version>\w+)/users/$',views.UsersView.as_view()),
]

视图函数配置获取版本方式为URLPathVersioning

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:",request.version) # 打印版本 return HttpResponse("aaaa")

在浏览器中输入http://127.0.0.1:8000/v1/users/地址,服务端打印结果

request.version: v1

再把浏览器中的url地址更换为http://127.0.0.1:8000/v10/users/,刷新浏览器,服务端打印结果

request.version: v10

2.3 AcceptHeaderVersioning:基于accept请求头方式获取版本信息

在settings.py文件中添加如下配置

REST_FRAMEWORK = {
'VERSION_PARAM': "version", # 版本的参数,在url中可以体现
'DEFAULT_VERSION': 'V1', # 默认的版本
'ALLOWED_VERSIONS': ['v1', 'v2','v3'] # 允许的版本
}

urls.py设定为

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^users/$',views.UsersView.as_view()),
]

视图函数定义

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import AcceptHeaderVersioning class UsersView(APIView):
versioning_class=AcceptHeaderVersioning def get(self,request,*args,**kwargs): print("request.version:",request.version) # 获取版本信息 return HttpResponse("aaaa")

用浏览器打开http://127.0.0.1:8000/users/的url地址

request.version: V1

由于在settings.py文件中已经设定了默认的版本是v1,所以在服务端后台获取到的版本是v1

把settings.py中定义的默认版本更改变v2或者v3,再次刷新浏览器,后台打印的版本信息又会跟着改变

request.version: V2

2.4 NamespaceVersioning:基于django路由系统的namespace

urls.py设定为

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^v1/users/',([url(r'test/',views.UsersView.as_view(),name='test1')],None,'v1')),
url(r'^v2/users/',([url(r'test/',views.UsersView.as_view(),name='test2')],None,'v2')),
]

视图函数定义

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import NamespaceVersioning class UsersView(APIView):
versioning_class=NamespaceVersioning def get(self,request,*args,**kwargs):
print("request.version:",request.version) # 获取版本信息 return HttpResponse("aaaa")

用浏览器打开http://127.0.0.1:8000/v1/users/test/的url地址

request.version: V1

把url的地址更换为http://127.0.0.1:8000/v2/users/test/,刷新浏览器,后台打印信息如下

request.version: V2

2.5 HostNameVersioning由于要更换电脑的主机名称,所以这里不再进行测试

3. versioning_class的全局配置

在视图函数中定义versioning_class,只能作用于单个类,

如果想整个项目都使用同一种方法来进行版本控制,就可以在settings.py文件中定义全局的versioning_class

settings.py中配置默认的versioning_classURLPathVersioning

REST_FRAMEWORK={
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
}

在前面查看到BaseVersioning的源码时,可以看到还有几个参数可以在settings.py文件中定义的

class BaseVersioning(object):
default_version = api_settings.DEFAULT_VERSION
allowed_versions = api_settings.ALLOWED_VERSIONS
version_param = api_settings.VERSION_PARAM

再来看看这几个参数配置项的作用

REST_FRAMEWORK={			# 默认使用URLPathVersioning类来获取版本信息
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
'VERSION_PARAM':"version", # 版本的参数,在url中可以体现
'DEFAULT_VERSION':'V1', # 默认的版本
'ALLOWED_VERSIONS':['v1','v2'] # 允许的版本
}

修改urls.py文件,使url可以匹配任意长度的字符url

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^(?P<version>\w+)/users/$',views.UsersView.as_view()),
]

在浏览器中分别输入http://127.0.0.1:8000/v1/users/http://127.0.0.1:8000/v2/users/

都可以获取到正确的响应信息

再在浏览器中输入http://127.0.0.1:8000/v3/users/时,浏览器中出现了报错

从这里可以知道,在settings.py文件中设定的url中允许的版本只能是v1或v2,在浏览器中输入的版本是v3,所以就会出现错误了

Django REST framework中的版本控制的更多相关文章

  1. Django REST framework 中文文档

    Django REST framework介绍 现在前后端分离的架构设计越来越流行,业界甚至出现了API优先的趋势. 显然API开发已经成为后端程序员的必备技能了,那作为Python程序员特别是把Dj ...

  2. 在django restful framework中设置django model的property

    众所周知,在django的model中,可以某些字段设置@property和setter deleter getter,这样就可以在存入数据的时候进行一些操作,具体原理请参见廖雪峰大神的博客https ...

  3. JWT验证机制【刘新宇】【Django REST framework中使用JWT】

    JWT 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证.我们不再使用Session认证机制,而使用Json Web Token认证机制. 什么是JWT Json web t ...

  4. Django REST framework 中 3 种类视图的对比

    相较于使用基于方法(function based)的视图,我们更加倾向使用基于类(class based)的视图.接下来,你将看到这是一个强大的模式,是我们能够重用公共的功能,并且,帮我们减少重复的造 ...

  5. Django REST framework 中的视图

    1.Request REST framework传入视图的request对象不再是Django默认的Httprequest对象,而是DRF提供的扩展类的Request类的对象 常用属性 request ...

  6. DRF (Django REST framework) 中的视图类

    视图说明 1. 两个基类 1)APIView rest_framework.views.APIView APIView是REST framework提供的所有视图的基类,继承自Django的View父 ...

  7. DRF (Django REST framework) 中的Request 与 Response

    DRF中的Request 与 Response 1. Request - REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST f ...

  8. Django REST framework基础:版本控制

    DRF的版本控制 为什么需要版本控制 API 版本控制允许我们在不同的客户端之间更改行为(同一个接口的不同版本会返回不同的数据). DRF提供了许多不同的版本控制方案. 可能会有一些客户端因为某些原因 ...

  9. Django REST framework 中的序列化器

    在此之前定义一个序列化工具:     views中的的代码 from rest_framework.viewsets import ModelViewSet from .models import B ...

随机推荐

  1. bootstrap-table操作之“删除”

    最近在做一个新的后台管理系统,在对数据进行操作时需要写一个"删除"功能,如图所示: 下面我来描述一下实现过程中出现的bug以及解决方法: 1.href值为空(href=" ...

  2. 【Java学习笔记之十五】Java中的static关键字解析

    Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...

  3. NOI 2004 郁闷的出纳员

    Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常 ...

  4. [51nod1671]货物运输

    公元2222年,l国发生了一场战争. 小Y负责领导工人运输物资. 其中有m种物资的运输方案,每种运输方案形如li,ri.表示存在一种货物从li运到ri. 这里有n个城市,第i个城市与第i+1个城市相连 ...

  5. 如何设置让网站禁止被爬虫收录?robots.txt

    robot.txt只是爬虫禁抓协议,user-agent表示禁止哪个爬虫,disallow告诉爬出那个禁止抓取的目录. 如果爬虫够友好的话,会遵守网站的robot.txt内容. 一个内部业务系统,不想 ...

  6. 修真院java后端工程师学习课程--任务1(day one)

    这是我从学习资料-线下报名-北京报名截取的报名截图,从图中我们可以看出我们的报名对象应该有姓名,qq,修真类型,预计入学时间,毕业院校,线上学号,日报链接,立愿,辅导师兄等属性,其中线上学号是主码. ...

  7. dedecms标签大全

    今天用了1个小时的时间整理了dedecms标签大全,非常经典,非常经典的织梦dedecms标签,希望对大家制作dedecms网站有帮助      channel_____栏目   dede_arcty ...

  8. FORM ACTION=""

    FORM ACTION=""  如果什么都不写,就表示提交到当前页

  9. Codeforces 895C - Square Subsets 状压DP

    题意: 给了n个数,要求有几个子集使子集中元素的和为一个数的平方. 题解: 因为每个数都可以分解为质数的乘积,所有的数都小于70,所以在小于70的数中一共只有19个质数.可以使用状压DP,每一位上0表 ...

  10. vue不是内部或外部命令,配置一个Path系统变量就可以解决

    作为一个vue小白,最近为vue安装真是操碎了心.无论怎么查找网上的教程,还是解决不了"vue不是内部或外部的命令"诸如此类的问题.好在功夫不负有心人,终于在多次的试验下,成功解决 ...