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. 达到目标方式交到主视图类涵数解决,获得要求的回应結果,回到给前台接待

评论(0条)

刀客源码 游客评论