美文网首页
Django REST framework(二): DRF请求

Django REST framework(二): DRF请求

作者: 是立品啊 | 来源:发表于2020-07-12 22:34 被阅读0次

DRF请求生命周期解析

  1. CBV的路由,调用视图的as_view(),一般业务视图很少定义自己的as_view(),所有会找到父类的as_view(),所以请求走的是APIViewas_view()函数
  2. APIViewas_view调父类的(django原生)的as_view:view = super().as_view(**initkwargs),还禁用了csrf认证,return csrf_exempt(view)
  3. 在父类的as_viewdispatch方法请求走的又是APIViewdispatch
  4. 完成任务方法交给视图类的请求函数处理,得到请求的响应结果,返回给前台

请求步骤拆解

1. 请求进来走的是APIViewas_view()函数

APIViewas_view()函数主要做了两件事

  • 调用父类的as_view,就是Viewas_view()方法
  • 禁用scrftoken认证:csrf_exempt(view)
class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

    # Allow dependency injection of other settings to make testing easier.
    settings = api_settings

    schema = DefaultSchema()

    @classmethod
    def as_view(cls, **initkwargs):
        """
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        """
        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().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view)

2. View中的as_view(),调用self.dispatch()完成请求的分发

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
        # 实例化产Mylogin的对象, self = Mylogin(**initkwargs)
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
                #dispatch返回什么,浏览器就会收到什么
            return self.dispatch(request, *args, **kwargs)
            # 对象在查找属性或者方法的时候,一定要默念,
            # 先从对象这里找,然后从产生对象的类里找,最后从父类里找
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
        
    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        # 这个方法仅仅是在给对象新增属性
        self.request = request
        self.args = args
        self.kwargs = kwargs

3.APIView类中定义了dispatch()方法,所有上一步调用self.dispatch()的时候会调用APIView的dispatch()

APIViewdispatch()做了以下5件事

  • 请求对象的二次封装:request = self.initialize_request(request, *args, **kwargs)
  • 请求之前发起三大认证,入口函数是self.initial(request, *args, **kwargs),认证不通过,抛出异常
  • 发出请求:response = handler(request, *args, **kwargs)
  • 请求结果交给渲染模块,按照前端要求的渲染类型,返回给前端elf.response = self.finalize_response(request, response, *args, **kwargs)
  • 返回请求结果
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
        # 请求的二次封装
        request = self.initialize_request(request, *args, **kwargs)
        self.request = 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)
        # 认证不通过,抛出异常
        except Exception as exc:
            response = self.handle_exception(exc)
        #finalize_response渲染模块
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

相关文章

网友评论

      本文标题:Django REST framework(二): DRF请求

      本文链接:https://www.haomeiwen.com/subject/vaamcktx.html