欢迎来到Cecilia陈的博客

孤独,是人一生最好的修行。

03 drf 请求模块

一、drf安装与使用

  1. 安装drfpip3 install djangorestframework

  2. settings.py注册app:

    INSTALLED_APPS = [
        ...
        'rest_framework'
    ]
    
  3. 基于cbv完成满足restful规范的接口

    # 视图层
    from rest_framework.views import APIView
    from rest_framework.response import Response
    # CBV接口
    class Test(APIView):
        def get(self,request,*args,**kwargs):
            print(request.GET)
            print(request.META)
    
            return Response({
                'status': 0,
                'msg': 'get ok'
            })
        
        def post(self,request,*args,**kwargs):
            print(request.POST)
            
            return Response({
                'status': 0,
                'msg': 'post ok',
            })
    
    # 路由层
    urlpatterns = [
        url(r'^api/', views.Test.as_view()),
    ]
    

二、drf CBV源码分析

  • 首先在路由层中注册CBV通过as_view()方法实现CBV,这个和django实现CBV的方法一致。但是drf在CBV中进行了一些其他处理。比如,虽然还是调用的父类的as_view来得到view,但返回时局部禁用了csrf认证csrf_exempt(view)
  • 当请求来的时候,路由视图函数映射关系匹配成功时就会进入请求分发的dispatch()方法.
  • dispatch()方法内在分发执行视图方法前,完成了
    • 二次封装request:self.initialize_request(request, *args, **kwargs)
    • 三大认证:self.initial(request, *args, **kwargs)
  • 在视图方法处理完请求后
    • 出现异常的处理:self.handle_exception(exc)
    • 二次封装response:self.finalize_response(request, response, *args, **kwargs)
'''rest_framework/views.py -> class APIView(view):中'''
	@classmethod
    def as_view(cls, **initkwargs):
        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对象
        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        return csrf_exempt(view)
'''rest_framework/views.py -> class APIView(view):中'''
    def dispatch(self, request, *args, **kwargs):
        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)
            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

注意:接下来大部分关于drf的源码都会从dispatch方法为起点开始分析

三、请求模块源码分析

  • drf的APIView类:重写了as_view(),但主体逻辑还是调用父类View的as_view(),局部禁用了csrf认证

    重点:所有继承drf的基本视图类APIView的视图类,都不在做csrf认证校验

  • drf的APIView类:重写了dispatch(),在内部对request进行了二次封装

    # 二次封装request
    request = self.initialize_request(request, *args, **kwargs)
    
  • initialize_request方法内部源码分析

    • 返回了Request类的实例化对象。
    • Request类中的__init__方法中将原来的request放到了self._request
    • 所有的拼接参数都解析到query_params中所有数据包数据都被解析到data中,通过@property装饰器将方法属性包装成数据属性。
    • query_params和data属于QueryDict类型,可以通过 .dict() 转化成原生dict类型
  • Request类内部实现了 .拦截方法 __getattr__来取值,可以直接取到_request中的内容

# CBV接口
class Test(APIView):
    
    def get(self,request,*args,**kwargs):
        print(request._request.GET) # 直接找原来的request
        print(request.GET)  # 通过内部的getattr来找
        print(request.META) # 通过内部的getattr来找

        # query_params转化为原生dict,拼接参数数据
        print(request.query_params.dict())
        # 数据包数据
        print(request.data)
        # 请求头参数
        print(request.META)
        

        return Response({
            'status': 0,
            'msg': 'get ok'
        })

    def post(self,request,*args,**kwargs):
        # 通过内部的getattr来找
        print(request.POST)

        # QueryDict转化为原生dict
        print(request.query_params.dict())
        print(request.data.dict())

        return Response({
            'status': 0,
            'msg': 'post ok',
        })
posted @ 2019-11-23 18:55  Cecilia陈  阅读(123)  评论(0编辑  收藏  举报