APIView源码解析:
class APIView(View):
过程:
从as_view()方法开始,创建一个实例,再调用dispatch()方法,dispatch()方法里面也有五步,分别是:记录各个参数,初始化请求方法(initialize_request()),initial()方法,根据得到的请求方法去处理或处理异常,最后统一处理response。初始化请求方法里面构建了一个新的request,在request里边获取了输入转换器,认证器,内容决策器和输入内容,initial方法里边又去执行内容决策,确定决策版本,执行认证,检查权限,检查节流,然后在去处理请求方法,所以在dispatch()方法中initial里边,它帮我们执行了认证和检查权限和检查节流,所以我们只要在类中使用restframework框架中的APIView类,然后写视图函数,调用as_view()方法就可以做到认证和节流了。这就是这个restframework框架给开发者带来的好处,就很方便我们去维护代码。
从入口开始看代码:
as_view():
@classmethod
def as_view(cls, **initkwargs):
# 如果他是QuerySet的一个实例
if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
def force_evaluation():
# 翻译:不要直接计算“.queryset”属性,因为结果将被缓存并在请求之间重用请改用“.all()”或调用“.get_queryset()”
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
# 该走这里了,调用父类的as_view() --- 父类的as_view()核心是dispatch() >> 跳转到dispatch()
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
# Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
# 豁免csrf检测, 返回view
return csrf_exempt(view) # 函数里面套函数,这个一个装饰器!!!
意外收获:
# FBV中调用的函数不能使用post请求,否则会出现403跨域请求,把装饰器放在函数上可以豁免csrf检测
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
return HttpResponse("嘿嘿,我还是进来了!")
as_view()的核心是dispatch() >>
dispatch():
- 记录各个参数
- initializer_request() <<
- initial <<
- 根据得到的请求方法去处理,或处理异常
- 最后统一处理response
# 源码
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
# 跳转看一看 >> initializer_request()
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 再跳一跳 >> initial()
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
dispatch() >> initialize_request()
initialize_request():
- 获取文本
- 使用Django中的request构建了一个新的request。
- 获得了输入转换器,认证器,内容决策器,输入的内容
# 源码
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
# 解析上下文
parser_context = self.get_parser_context(request)
# 构建了一个新的request
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
dispatch() >> initial()
initial(): --- 核心
- 获取格式化后缀
- 执行内容决策
- 拆包
- 进行决策版本,确定版本
- 执行认证(重点)
- 检查权限
- 检查节流
#源码
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)