DRF基本源码、Resquest及Response对象

1、CBV(Class Base Views)
思路–路由层–as——view()内的闭包函数内存地址
path(‘test/’,views.TestView.as_view())
as_view()
@classonlymethod
def as_view(cls, **initkwargs):
#1、内部有view函数、并且有着对外层函数的引用 cls
# return view *后返回内层函数名、说明是个闭包函数
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, ‘get’) and not hasattr(self, ‘head’):
self.head = self.get
self.setup(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
#2、django任务启动的时候、path(‘test/’,views.TestView.as_view())产生变形
path(‘test/’,views.view)
views内存地址对应
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, ‘get’) and not hasattr(self, ‘head’):
self.head = self.get
self.setup(request, *args, **kwargs)

return self.dispatch(request, *args, **kwargs)
#3、本质是在执行self.dispatch
def dispatch(self, request, *args, **kwargs):
#4、*终通过反射getattr去获得方法
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
#5、执行get方法,传入参数
return handler(request, *args, **kwargs)

小结
CBV通过View类as_view()内的闭包函数view的内存地址
执行dispatch通过反射、判断post,get请求
2、APIView的源码、执行流程
from rest_framework.views import APIView
#django内部–APIView继承了View
class APIView(View):
settings = api_settings
schema = DefaultSchema()
@classmethod
def as_view(cls, **initkwargs):
# super()对父类as_view()的调用
#1、APIView类的as_view内部使用的是 View 内部的 as_view内的view闭包函数
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
#2、请求匹配成功执行View类的as_view()内的view内存地址、但是
#返回值增加了 csrf_exempt装饰、所以继承APIView的接口都无需csrf校验
return csrf_exempt(view)

说明:
drf对view的dispatch进行了重写
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
#所以drf中的request已经不是django中的reqeust了,而是drf自己的request
3、Request对象分析
class Request:
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
assert isinstance(request, HttpRequest), (
‘The `request` argument must be an instance of ‘
‘`django.http.HttpRequest`, not `{}.{}`.’
.format(request.__class__.__module__, request.__class__.__name__)
)
self._request = request #原生的request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty

def __getattr__(self, attr):
try:
#重写了getattr、 通过反射,将原生request对象,以及属性和方法取出
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)

”’query_params方法被@property装饰器将方法封装成属性
get请求的数据都在这里取
”’
@property
def query_params(self):
“””
More semantically correct name for request.GET.
“””
return self._request.GET

”’
通过@property装饰器将data方法封装成属性
data方法:它是一个字典,post请求不管使用什么编码,传过来的数据,都在request.data
”’
@property
def data(self):
if not _hasattr(self, ‘_full_data’):
self._load_data_and_files()
return self._full_data

#文件的数据
@property
def FILES(self):
# Leave this one alone for backwards compat with Django’s request.FILES
# Different from the other two cases, which are not valid property
# names on the WSGIRequest class.
if not _hasattr(self, ‘_files’):
self._load_data_and_files()
return self._files
总结:

-虽然视图类中request对象变成了drf的request,但是用起来,跟原来的一样,只不过它多了一些属性
-request.data #post请求提交的数据,不论什么格式,都在它中取出来
-requst.query_params# get请求提交的数据(查询参数)
注意:请求头是存放在request.META中,获取请求头的信息可以从该属性中获取
4、Response对象源码分析
from rest_framework.response import Response

class Response(SimpleTemplateResponse):
“””
An HttpResponse that allows its data to be rendered into
arbitrary media types.
“””

def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
#data: 要返回的数据–字典
#status: 返回的状态码、默认200
#template_name: 渲染的template模板名、可自定制
#headers: 响应头、可以放东西
#content_type: 响应编码格式 application/json和text/html
注意:from rest_framework import status
在stauts模块下、所用到的状态码都被定义成了常量
响应数据数据格式配置。
-局部使用:对某个视图类有效
-在视图类中写如下
from rest_framework.renderers import JSONRenderer
renderer_classes=[JSONRenderer,]-全局使用:全局的视图类,所有请求,都有效
-在setting.py中加入如下
REST_FRAMEWORK = {
‘DEFAULT_RENDERER_CLASSES’: ( # 默认响应渲染类
‘rest_framework.renderers.JSONRenderer’, # json渲染器
‘rest_framework.renderers.BrowsableAPIRenderer’, # 浏览API渲染器
)
}
5、对Response对象的重新封装
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self,code=100,msg=’成功’,data=None,status=None,headers=None,**kwargs):
dic = {‘code’: code, ‘msg’: msg}
if data:
dic = {‘code’: code, ‘msg’: msg,’data’:data}
dic.update(kwargs)
super().__init__(data=dic, status=status,headers=headers)