zoukankan      html  css  js  c++  java
  • Django(47)drf请求生命周期分析

    前言

      一般我们写完序列化以后,我们就会开始写视图了,drf中我们一般使用CBV的方式,也就是类视图的方式,最基础的我们会使用from rest_framework.views import APIViewAPIView继承自View,关于视图的详解,我们后续再细讲。本章介绍drf的请求生命周期
     

    前置准备工作

    我们先写一个视图类TestView,代码如下:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            return Response("drf get ok")
        def post(self, request, *args, **kwargs):
            return Response("drf post ok")
    

    注意:这里的Response必须是drf下的Response,不能是Django原生的HttpResponse或者是JsonResponse,否则会出错

    接着,在urls.py中配置路由,如下

    urlpatterns = [
        path('test/', views.TestView.as_view(), name="Test"),
    ]
    

    然后我们访问http://127.0.0.1:8000/drf/test/,会出现下图样式,代表请求成功

    接着我们在接口工具中使用POST请求方式访问,返回结果如下:

    "drf post ok"
    

    以上2种访问方式都成功了,接下来我们分析其中的请求过程以及原理
     

    请求生命周期分析

    首先我们先从路由配置中看到views.TestView.as_view(),调用的是TestView类视图下的as_view方法,但是我们上面定义该方法的时候,没有重写as_view()方法,所以会调用父类APIView中的as_view方法,源码如下:

    @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.
        """
    
        # 判断queryset是否是QuerySet对象
        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
    
        # 调用父类的as_view方法
        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认证
        return csrf_exempt(view)
    

    通过这行代码view = super().as_view(**initkwargs),可以知道APIViewas_view方法也调用了父类Viewas_view方法,源码如下:

    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):
            self = cls(**initkwargs)
            # 如果有get属性,没有head属性,那么head就是get
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
    
            # 初始化所有视图方法共享的属性
            self.setup(request, *args, **kwargs)
    
            # 如果没有request属性,报异常
            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
    

    as_view方法返回的是viewview返回的是dispatch方法,dispatch方法也是调用的APIView下的dispatch方法,源码如下:

    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对象
        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
            # 获取request的请求方法
            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)
        
        # 返回一个response响应对象
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    

    dispatch返回一个response响应对象,得到请求的响应结果,返回给前台
     

    总结

    1. url请求走的是APIViewas_view函数
    2. APIViewas_view调用父类(django原生)的as_view,还禁用了csrf认证
    3. 在父类的as_view中的dispatch方法请求走的又是APIViewdispatch
    4. 完成任务方法交给视图类函数处理,得到请求的响应结果,返回给前台
  • 相关阅读:
    ByteBuffer的mark、position、limit、flip、reset,get方法介绍ok
    java.nio.ByteBuffer的flip、rewind和compact几个方法的区分使用
    maven之一:maven安装和eclipse集成
    Java 8 函数式接口
    Lambda 表达式
    jdk8十大新的特性
    阿里巴巴73款开源产品列表,值得收藏
    【Java】java.util.Objects 工具类方法研究
    ARIMA 模型简单介绍
    python 二维数组取值
  • 原文地址:https://www.cnblogs.com/jiakecong/p/14858485.html
Copyright © 2011-2022 走看看