Jiang's blog

DRF源码解析4--版本控制组件的封装

Word count: 577Reading time: 2 min
2020/02/22 Share

一.DRF中APIView的initial()方法初始化版本信息

在讲到DRF对ruquest的封装时,返回新封装的Request后,DRF执行了initial()方法对组件的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
def initial(self, request, *args, **kwargs):
# 版本控制组件
version, scheme = self.determine_version(request, *args, **kwargs)
# 将版本空值信息写入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)

1.1重写determine_version()自定制版本信息

1
2
3
4
5
6
7
8
9
10
  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)
# self.versioning_class是drf配置默认的类,说明我们自定义版本时要重写这个方法
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)

二.rest_framework.versioning提供的版本控制方法

versioning

2.1 BaseVersioning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class BaseVersioning:
# default_version(None), allowed_versions(None), version_param可以在settings中重新配置
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):
# 在继承该类时要重写determine_version(方法)
msg = '{cls}.determine_version() must be implemented.'
raise NotImplementedError(msg.format(
cls=self.__class__.__name__
))

def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
# 和django.urls.reverse大致相同,
# 但可以选择接受一个请求并返回使用请求获取基本URL的标准URL。
return _reverse(viewname, args, kwargs, request, format, **extra)

def is_allowed_version(self, version):
if not self.allowed_versions:
return True
return ((version is not None and version == self.default_version) or
(version in self.allowed_versions))

2.2 URLPathVersioning

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
38
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):
# self.version_param,self.default_version是父类中的属性,可以自定义
version = kwargs.get(self.version_param, self.default_version)
if version is None:
# 如果没有自己配置默认为DRF默认的版本信息
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
# self.version_param就是版本的key
kwargs[self.version_param] = request.version

return super().reverse(
viewname, args, kwargs, request, format, **extra

其他的类基本配置都差不多

CATALOG
  1. 1. 一.DRF中APIView的initial()方法初始化版本信息
    1. 1.1. 1.1重写determine_version()自定制版本信息
  2. 2. 二.rest_framework.versioning提供的版本控制方法
    1. 2.1. 2.1 BaseVersioning
    2. 2.2. 2.2 URLPathVersioning