3月7日学习内容整理:restframework的版本信息组件
补充:
1)获取请求的代理IP:request.META.get("HTTP_X_FORWARDED_FOR") 这样就是取到了请求所使用的代理IP,但前提是必须要保留请求的原始IP
2)在CBV中,request._request.GET我们可以用request.query_params来代替
在restful规范中,提示我们api中应当保留版本信息,restframework就为我们提供了获取版本信息的组件
版本信息的存储位置有很多,比如存在URL中,GET数据中,请求头中等,下面就分情况来说明不同位置如何使用rest的版本组件
一、利用URL中的GET数据传
1、代码实现:自定义版本类,在自定义view类中定义好versioning_class 参数
# 请求URL #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) return HttpResponse('用户列表')
2、通常我们不用自定义去写,只要继承rest中内置的版本类就可以了,下面这个类就是专门处理版本信息保存在URL中的GET数据里面的内置类,我们自定义的版本类继承它就可以了或者直接在配置文件中配置为全局使用,从GET数据中取的话就涉及到key的问题了,这个配置文件中可以设置
from rest_framework.versioning import QueryParameterVersioning
二、利用URL传
其实也不用我们自定义版本类,下面这个内置类就是专门处理版本信息保存在URL中的,在配置文件中设置全局使用就可以了
from rest_framework.versioning import URLPathVersioning
在url文件中:
urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view()), ]
三、配置文件的设置
REST_FRAMEWORK = { # 设置全局使用的版本类,这里用的是从URL的有名分组中提取版本信息 "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning", # 设置版本信息的默认值 "DEFAULT_VERSION": 'v1', # 设置哪些版本是支持访问的 "ALLOWED_VERSIONS": ['v1', 'v2'], # 这个参数就是设置当版本信息保存在URL的GET数据中时key的值 "VERSION_PARAM": 'version', }
四、源码流程:
1、APIView的dispatch方法,首先重新封装了request为Request对象,再执行initial方法,其中的determine_version方法就是用来获取版本信息
def initial(self, request, *args, **kwargs): # 版本操作 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)
2、执行API中的determine_version,就会实例配置文件中设置的版本类对象,继而返回一个元组,第一个元素是版本类对象的determine_version方法的返回值,第二个元素就是版本类的实例对象,以URLPathVersioning为例,这里返回的元素就会返回到initial方法中用来给request封装属性如上第1步
def determine_version(self, request, *args, **kwargs): # versioning_class就是配置文件中对应的版本类 if self.versioning_class is None: return (None, None) # 这里就是实例化版本类对象 scheme = self.versioning_class() # 返回一个元组 # 第一个元素是版本类对象的determine_version方法的返回值 # 第二个元素就是版本类的实例对象 return (scheme.determine_version(request, *args, **kwargs), scheme)
3、执行版本类对象的determine_version方法,取URL的中对应的key中的版本信息,这个key就是配置文件中设置的,若为空,则是配置文件中设置的默认值,最后把版本信息返回
class URLPathVersioning(BaseVersioning): invalid_version_message = _('Invalid version in URL path.') def determine_version(self, request, *args, **kwargs): # 这里就是在取URL的GET数据中对应的key中的版本信息,若为空,则是配置 # 文件中设置的默认值 # 最后把版本信息返回 version = kwargs.get(self.version_param, self.default_version) if not self.is_allowed_version(version): raise exceptions.NotFound(self.invalid_version_message) return version
五、执行完版本操作后request会被封装两个属性
# 1. 获取版本 print(request.version) # 2. 获取处理版本的对象,也就是配置文件中设置的版本类对象,或者是自定义版本类的实例对象 print(request.versioning_scheme)
版本类的实例对象还有reverse方法,用来反向解析URL地址的,其实本质上还是调用django的reverse反向解析方法,返回的URL是完整的,带域名的
# 反向生成URL(rest framework) # viewname就是别名,也就是url中定义的name属性值,还要把request传过去 u1 = request.versioning_scheme.reverse(viewname='uuu', request=request)