APIView源码解析

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():

  1. 记录各个参数
  2. initializer_request() <<
  3. initial <<
  4. 根据得到的请求方法去处理,或处理异常
  5. 最后统一处理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():

  1. 获取文本
  2. 使用Django中的request构建了一个新的request。
  3. 获得了输入转换器,认证器,内容决策器,输入的内容
# 源码
	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(): --- 核心

  1. 获取格式化后缀
  2. 执行内容决策
  3. 拆包
  4. 进行决策版本,确定版本
  5. 执行认证(重点)
  6. 检查权限
  7. 检查节流
#源码
    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)

APIView所有方法:

原文地址:https://www.cnblogs.com/lance-lzj/p/13853064.html