Django rest framework 之版本
一、通过 QueryParameterVersioning 获取版本
通过 QueryParameterVersioning 从 get 请求中获取版本信息:
1、新建 app,名为 api,Project/urls.py:
from django.contrib import admin
from django.urls import path, include
from app.views import IndexView, OrderView, UserInfo
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')),
path('api/v1/index/', IndexView.as_view()),
path('api/v1/order/', OrderView.as_view()),
path('api/v1/info/', UserInfo.as_view()),
]
2、api/urls.py
from django.urls import path, re_path
from api.views import UserView
urlpatterns = [
path('users/', UserView.as_view()),
]
3、api/views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.versioning import QueryParameterVersioning
class UserView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
print(request.version) # 获取版本信息
return HttpResponse('版本信息')
4、settings.py
# 设置全局认证
REST_FRAMEWORK = {
"DEFAULT_VERSION": 'v1', # 默认的版本
"ALLOWED_VERSIONS": ['v1', 'v2'], # 允许的版本
"VERSION_PARAM": 'version' # GET方式url中参数的名字 ?version=xxx
}
5、访问:<http://127.0.0.1:8000/api/users/?version=v2>,通过 QueryParameterVersioning 从 get 请求中获取版本信息:

当访问不存在的版本时(v3 不在 settings 中设置的允许版本范围内):

二、通过 URLPATH 获取
在上面我们通过 QueryParameterVersioning 可以获取版本信息,但是每次以 <http://127.0.0.1:8000/api/users/?version=v3> 这种方式传参,未免太过麻烦,也不简洁美观。rest framework 推荐使用 URLPATH 来获取版本信息。
1、api/urls.py
from django.urls import path, re_path
from api.views import UserView
urlpatterns = [
# path('users/', UserView.as_view()),
# 修改如下,通过正则来匹配版本信息
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view())
]
2、api/views.py
URLPathVersioning 可以从 URL 路径中获取版本信息,而不是获取 URL 中的参数:
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.versioning import QueryParameterVersioning
from rest_framework.versioning import URLPathVersioning
class UserView(APIView):
# versioning_class = QueryParameterVersioning
versioning_class = URLPathVersioning # 添加这个
def get(self, request, *args, **kwargs):
print(request.version)
return HttpResponse('版本信息')
3、访问:http://127.0.0.1:8000/api/v2/users/

是不是比之前简洁多了,也美观多了,如果你想全局配置每个视图,也可以再 settings 中设置:
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
}
三、反向解析 URL
一直以来我们很少用到 URL 中的 name 参数(别名),但是有时候我们与 reverse() 方法用来作反向解析,从而推断出访问的 URL,这在有些场合还是很有作用的:
1、api/uris.py
from django.urls import path, re_path
from api.views import UserView
urlpatterns = [
# path('users/', UserView.as_view()),
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user')
]
2、api/views.py
# viewname: URL name 参数,request 对象
reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra)
class UserView(APIView):
# versioning_class = QueryParameterVersioning
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
print(request.version)
print(request.versioning_scheme)
url_path = request.versioning_scheme.reverse(viewname='api_user', request=request)
print(url_path)
return HttpResponse('版本信息')

四、源码分析
1、dispatch()
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 对原生的 request 对象进行加工,丰富了
# request= Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)
# 第一个参数为原生的 request 对象,
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs) # 初始化方法
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
2、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.
# 获取版本信息以及 scheme
version, scheme = self.determine_version(request, *args, **kwargs)
# 将版本信息以及 scheme 封装到 request 中
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)
3、determine_version()
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)
"""
# 从 versioning_class 中获取,如果没有配置则返回两个 None
if self.versioning_class is None:
return (None, None)
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)
4、api_settings
class APIView(View):
# The following policies may be set at either globally, or per-view.
....
# 从配置文件中加载
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
URLPathVersioning 源码分析
1、URLPathVersioning
class URLPathVersioning(BaseVersioning):
"""
To the client this is the same style as `NamespaceVersioning`.
The difference is in the backend - this implementation uses
Django's URL keyword arguments to determine the version.
An example URL conf for two views that accept two different versions.
# 提供的 URL 配置示例
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
]
GET /1.0/something/ HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in URL path.')
def determine_version(self, request, *args, **kwargs):
"""版本控制"""
# 从 version_param 获取版本信息,如果没有则使用默认的 default_version
version = kwargs.get(self.version_param, self.default_version)
if version is None:
version = self.default_version
# 如果版本不在允许范围内,则报错
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
"""反向解析"""
if request.version is not None:
kwargs = {} if (kwargs is None) else kwargs
kwargs[self.version_param] = request.version
return super(URLPathVersioning, self).reverse(
viewname, args, kwargs, request, format, **extra
)
2、version_param
class BaseVersioning(object):
default_version = api_settings.DEFAULT_VERSION # 默认版本
allowed_versions = api_settings.ALLOWED_VERSIONS # 允许版本
version_param = api_settings.VERSION_PARAM # 默认配置版本信息
def determine_version(self, request, *args, **kwargs):
msg = '{cls}.determine_version() must be implemented.'
raise NotImplementedError(msg.format(
cls=self.__class__.__name__
))
settings 中的配置:
"DEFAULT_VERSION": 'v1', # 默认的版本
"ALLOWED_VERSIONS": ['v1', 'v2'], # 允许的版本
"VERSION_PARAM": 'version' # GET方式url中参数的名字 ?version=xxx
源码流程图

总结
- 从
get请求参数中获取版本信息:QueryParameterVersioning(不推荐) URLPATH中获取版本信息(推荐),可全局配置
Django rest framework 之版本的更多相关文章
- Django Rest framework 之 版本
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Django REST framework之版本,解释器,序列化
1 版本 2 解释器 3.序列化 1 版本 通过?后面传版本号有两种方法: 方法一 from django.shortcuts import render from rest_framework.vi ...
- 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 之 节流(三) ...
随机推荐
- 网络协议 7 - UDP 协议
网络协议五步登天路,我们一路迈过了物理层.链路层,今天终于到了传输层.从这一层开始,很多知识应该都是服务端开发必备的知识了,今天我们就一起来梳理下. 其实,讲到 UDP,就少不了 TCP.这俩 ...
- 【BZOJ3569】DZY Loves Chinese II
[BZOJ3569]DZY Loves Chinese II 题面 bzoj 题目大意: 给你一张\(N(1\leq N\leq 10^5)\)个点\(M(1\leq M\leq 5\times 10 ...
- 关于三层架构和MVC模式的思考
MVC模式 核心: 1.解耦Model和View,即使得Model可以被不同的展示,比如一批统计数据可以分别用柱状图.饼图表示 2.Controller用来保证Model和View的同步 Model ...
- [TJOI2009]猜数字(洛谷 3868)
题目描述 现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示.其中第二组中的数字是两两互素的.求最小的非负整数n,满足对于任意 ...
- [Usaco2012 Feb] Cow Coupons
[Usaco2012 Feb] Cow Coupons 一个比较正确的贪心写法(跑得贼慢...) 首先我们二分答案,设当前答案为mid 将序列按照用券之后能省掉的多少排序,那么我们对于两种情况 \(m ...
- [BZ1925] [SDOI2010]地精部落
[BZ1925] [SDOI2010]地精部落 传送门 一道很有意思的DP题. 我们发现因为很难考虑每个排列中的数是否使用过,所以我们想到只维护相对关系. 当我们考虑新的一个位置时,给新的位置的数分配 ...
- 搭建Hadoop+Python的大数据开发环境
实验环境 CentOS镜像为CentOS-7-x86_64-Everything-1804.iso 虚机配置 节点名称 IP地址 子网掩码 CPU/内存 磁盘 安装方式 master 192.168. ...
- Spring Security教程之退出登录logout(十)
要实现退出登录的功能我们需要在http元素下定义logout元素,这样Spring Security将自动为我们添加用于处理退出登录的过滤器LogoutFilter到FilterChain.当我们指定 ...
- Java实现添加压缩文件
package junittest; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStr ...
- 【Linux脚本学习案例】shell脚本多通道并发执行存储过程
使用shell脚本开启多个子任务并发调用存储过程,存储过程按照通道处理数据,提高效率: 外层调用脚本: #!/bin/sh #------------------------------------- ...