DRF的APIView源码分析
DRF框架中的APIView继承于django框架的View
class APIView(View):
urls.py
from app01 import views
urlpatterns = [
path(‘books/<int:book_id>/‘, views.Books.as_view(), name=‘books‘),
].py
views.py
from rest_framework.views import APIView
APIView重写了View的as_view方法
@classmethod
def as_view(cls, **initkwargs): # cls是Book类
...
view = super().as_view(**initkwargs) #调用了父类View的as_view方法
view.cls = cls # 一切皆对象,将cls赋值给View的cls属性
view.initkwargs = initkwargs
# Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
return csrf_exempt(view) # 去除掉CSRF认证
View的as_view方法:
def as_view(cls, **initkwargs):
...
def view(request, *args, **kwargs): # 闭包函数
self = cls(**initkwargs) # 实例化book类的对象
if hasattr(self, ‘get‘) and not hasattr(self, ‘head‘):
self.head = self.get
return self.dispatch(request, *args, **kwargs)
return view
?分发函数dispatch
# 这里调用分发函数dispatch是APIVIEW的(查找顺序,先对象中,后类中,在父类中)
# APIVIEW的dispatch方法
def dispatch(self, request, *args, **kwargs):
# request是原生的request
self.args = args
self.kwargs = kwargs
# 这里将request对象进行了二次封装
request = self.initialize_request(request, *args, **kwargs)
self.request = request # 将二次封装后的request赋值给book对象的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) # get(request)
except Exception as exc:
# 异常捕获模块
response = self.handle_exception(exc)
# 渲染模块
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
看下initialize_request(request, *args, **kwargs)
from rest_framework.request import Request
def initialize_request(self, request, *args, **kwargs):
...
return Request(
request,
parsers=self.get_parsers(), # 参数解析
authenticators=self.get_authenticators(), # 认证
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
使用DRF的request.Request对原生的request进行了二次的封装
接着看下三大认证模块initial(self, request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
# 版本控制
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) # 频率检测
# 认证组件
建议用户:合法用户,非法用户,游客
# 游客:代表校验通过,直接进入下一步校验(权限校验)
# 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
# 非法用户:代表校验失败,抛出异常,返回403权限异常结果
# 权限组件
权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
# 认证通过:可以进入下一步校验(频率认证)
# 认证失败:抛出异常,返回403权限异常结果
# 频率组件
限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
# 没有达到限次:正常访问接口
# 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
流程分析图:
此外,DRF中通过重写__getattr__
方法,通过反射getattr
来访问原生的 request
,取出属性以及方法
# 原生的request被赋值给了self._request
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):
return self._request.GET
#视图类中
print(request.query_params) #get请求,地址中的参数
# 原来在
print(request.GET)