|
# restframework的APIView源码分析
1、还是通过路由中的点as_view()入手,返回的还是view函数地址和原生的request
@classmethod
def as_view(cls, **initkwargs):
if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
def force_evaluation():
raise RuntimeError(
'Do not evaluate the `.queryset` attribute directly, '
'as the result will be cached and reused between requests. '
'Use `.all()` or call `.get_queryset()` instead.'
)
cls.queryset._fetch_all = force_evaluation[这里不用看]
view = super(APIView, cls).as_view(**initkwargs)[继承父类View的方法,返回的还是self.dispatch,但是这里的self.dispatch,不是View的了而是自己写的APIView的]
view.cls = cls[一切皆对象,给view类的属性赋值]
view.initkwargs = initkwargs
return csrf_exempt(view)[去除局部跨站请求认证]
2、 APIView的dispatch方法
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
[把原生的request方法进行了封装,多了request.data等功能,重写了__getattr__方法,self._request,是原来的功能还能用,但是request已经不一样]
self.request = request[在返回函数中,以后的request就是封装过的了]
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)[]-[认证组件、权限组件、频率组件]
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)[对于返回的response进行不同处理,postman返回json数据,客户返回可视化页面]
return self.response
3、APIView的initial方法
def initial(self, request, *args, **kwargs):
# 认证组件:校验用户 - 游客、合法用户、非法用户
# 游客:代表校验通过,直接进入下一步校验(权限校验)
# 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
# 非法用户:代表校验失败,抛出异常,返回403权限异常结果
self.perform_authentication(request)
# 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
# 认证通过:可以进入下一步校验(频率认证)
# 认证失败:抛出异常,返回403权限异常结果
self.check_permissions(request)
# 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
# 没有达到限次:正常访问接口
# 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
self.check_throttles(request)小知识点补充from rest_framework.request import Request
# 只要继承了APIView,视图类中的request对象,都是新的,也就是上面那个request的对象了
# 老的request在新的request._request
# 以后使用reqeust对象,就像使用之前的request是一模一样(因为重写了__getattr__方法)
def __getattr__(self, attr):
try:
return getattr(self._request, attr) #通过反射,取原生的request对象,取出属性或方法
except AttributeError:
return self.__getattribute__(attr)
# request.data 感觉是个数据属性,其实是个方法,@property,修饰了
它是一个字典,post请求不管使用什么编码,传过来的数据,都在request.data
#get请求传过来数据,从哪取?
request.GET
@property
def query_params(self):
"""
More semantically correct name for request.GET.
"""
return self._request.GET
#视图类中
print(request.query_params) #get请求,地址中的参数
# 原来在
print(request.GET)
总结:入口还是点as_view方法--->>返回的是一个view的函数地址,这个view继承了之前的View的方法,所以返回值还是self.dispathc和原生的request----》》这个时候self.dispatch是APIView重写的里面把request进行封装,有额外拓展属性,eg:request.data,重写了__getattr__方法,以后的request就是封装的新request----》》在经过三个组件:认证组件、权限组件、频率组件---》》对于返回的Response对象进行不同处理,返回不同的结果,比如postman返回json,网站请求返回页面等
|
-
|
|