版本
# 链接资料
# 1. 版本控制介绍
API版本控制允许我们在不同的客户端之间更改行为(同一个接口的不同版本会返回不同的数据)。DRF提供了许多不同的版本控制方案。可能会有一些客户端因为某些原因已经不再维护了,但是我们后端的接口还是要不断的更新迭代的,这个时候通过版本控制返回不同的内容就是一种不错的解决方案。
其实说白了,我访问的是同一个视图,但是由于不同的版本,返回的参数是不一样的。那这个是怎么控制的呐?来我们继续往下介绍。
主要是配置settings.py版本信息,然后在参考把版本信息是反正url,还是请求头.....哪里哪里。。
# 2. 自定义版本
自定义:
http://127.0.0.1:8000/api/users/?version=v2
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):
#version = request._request.GET.get('version')
#print(version)
# version = request.query_params.get('version')
# print(version)
print(request.version)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.1 使用自带的版本
# 使用:
配置文件:
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', # 版本信息
"DEFAULT_VERSION": 'v1', # 默认版本号,默认值为None
"ALLOWED_VERSIONS": ['v1', 'v2'], # 允许请求的版本号,默认值为None
"VERSION_PARAM": 'version', # 识别版本号参数的名称,默认值为'version'
}
路由:
urlpatterns = [ # 主路由
url(r'^api/', include('api.urls')),
]
urlpatterns = [
# http://127.0.0.1:8000/api/v1/users/
# http://127.0.0.1:8000/api/v2/users/
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'),
]
# views.py
class UsersView(APIView):
permission_classes = []
def get(self, request, *args, **kwargs):
# 1. 获取版本 v1
print(request.version)
# 2. 获取处理版本的对象 <rest_framework.versioning.URLPathVersioning object at 0x000001C3AA7D3E10>
print(request.versioning_scheme)
# 3. 反向生成URL(rest framework) http://127.0.0.1:8000/api/v1/users/
u1 = request.versioning_scheme.reverse(viewname='uuu', request=request)
print(u1)
# 4. 反向生成URL /api/2/users/
u2 = reverse(viewname='uuu', kwargs={'version': 2})
print(u2)
return HttpResponse('用户列表')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 注意
在需要获取请求的版本号时,可以通过request.version
来获取版本号。
默认版本功能未开启,request.version
返回None。
开启版本支持功能,需要在配置文件中设置DEFAULT_VERSIONING_CLASS
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', # 版本信息
1
其他可选配置:
- DEFAULT_VERSION 默认版本号,默认值为None
- ALLOWED_VERSIONS 允许请求的版本号,默认值为None
- VERSION_PARAM 识别版本号参数的名称,默认值为'version'
request.version
request.versioning_scheme
request.versioning_scheme.reverse(viewname='uuu', request=request)
reverse(viewname='uuu', kwargs={'version': 2})
1
2
3
4
2
3
4
# 3. 更多支持的版本处理方式
# AcceptHeaderVersioning
请求头中传递的Accept携带version版本信息
GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
1
2
3
2
3
# URLPathVersioning(推荐使用)
URL路径中携带版本信息
urlpatterns = [
url( r'^(?P<version>(v1|v2))/bookings/$', bookings_list,name='bookings-list' ),
url( r'^(?P<version>(v1|v2))/bookings/(?P<pk>[0-9]+)/$',bookings_detail,name='bookings-detail')
]
1
2
3
4
2
3
4
# NamespaceVersioning
命名空间中定义
# bookings/urls.py
urlpatterns = [
url(r'^$', bookings_list, name='bookings-list'),
url(r'^(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail')
]
# urls.py
urlpatterns = [
url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))
]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# HostNameVersioning
主机域名携带 版本信息
GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json
1
2
3
2
3
# QueryParameterVersioning
查询字符串携带 版本信息
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
1
2
3
2
3
# 示例
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning'
}
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
class BookInfoSerializer2(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date')
class BookDetailView(RetrieveAPIView):
queryset = BookInfo.objects.all()
def get_serializer_class(self):
if self.request.version == '1.0':
return BookInfoSerializer
else:
return BookInfoSerializer2
# 127.0.0.1:8000/books/2/
# 127.0.0.1:8000/books/2/?version=1.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 源码流程
# 1.APIView下的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
# 获取的参数
# 把获取的参数,经过initialize_request构建成新的request
request = self.initialize_request(request, *args, **kwargs) # 封装requert
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 2. 进入认证self.initial(request, *args, **kwargs)
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 进入 self.determine_version(request, *args, **kwargs)
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)
scheme = self.versioning_class() # 获取是那种的版本信息方式
return (scheme.determine_version(request, *args, **kwargs), scheme) # 重点是这个determine_version
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
编辑 (opens new window)
← 接口访问控制(限流) 分页→