目录
一、DRF框架 - Django REST Framework
2-1 as_view方法源码 - 返回结果局部禁用Django自带的csrf组件,触发dispatch方法的执行
2-2 dispatch - 使用APIview的dispatch进行请求分发处理,对request进行了处理
2-3 initialize_request - 返回新处理的request,既包含了原有属性又增加了相应属性
2-4 request - 对request进行处理,getattr和setattr的处理
2-4-1 __getattr__处理对DRF内request内不存在属性的请求
2-4-2 request.data - 存储前台传输原body体内数据
2-4-3 request.query_params - 存储原始GET内数据
一、DRF框架 - Django REST Framework
1-1 DRF框架介绍 - 官方文档
Django REST框架是用于构建Web api的强大而灵活的工具包,即Django内置模块的拓展,可视为Django的第三方APP插件包。
- Web可浏览API对于开发人员来说是一个巨大的可用性胜利。
- 身份验证策略,包括OAuth1a和OAuth2的包。
- 同时支持ORM和非ORM数据源的序列化。
- 可自定义的——如果不需要更强大的功能,只需使用常规的基于功能的视图。
- 丰富的文档和强大的社区支持。
- 得到Mozilla、Red Hat、Heroku、Eventbrite等国际知名公司的使用和信任。
1-2 安装
- 方式一:pip3 install djangorestframework
- 方式二:pycharm图形化界面安装
- 方式三:pycharm命令行下安装(装在当前工程所用的解释器下)
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', # 组件注册 'rest_framework', ]
二、APIview源码分析
2-1 as_view方法源码 - 返回结果局部禁用Django自带的csrf组件,触发dispatch方法的执行
注意:
- 项目的启动流程:
- 项目启动 - urls路由内放入as_view()内存地址 - 接受请求 - 执行as_view() - 触发dispatch函数 - diaspatch进行视图函数的分发
@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. 将原始类存储在视图函数中。这允许我们在执行URLreverse查找时发现关于视图的信息。用于生成导航。 """ 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(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. # 局部禁用Django自带的csrf组件,返回的结果实际是一个函数的内存地址 # 当在路由中进配置时,as_view()将内存地址放入执行 return csrf_exempt(view)
2-2 dispatch - 使用APIview的dispatch进行请求分发处理,对request进行了处理
注意: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. ' .dispatch() '与Django的常规调度非常相似, 但是有额外的钩子用于启动、finalize和异常处理。 """ self.args = args self.kwargs = kwargs # request参数为原始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 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) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
2-3 initialize_request - 返回新处理的request,既包含了原有属性又增加了相应属性
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. 返回初始请求对象。 """ parser_context = self.get_parser_context(request) # 类实例化产生了对象,产生新的DRF的request return Request( request, # 用于解析(获取解析器) parsers=self.get_parsers(), # 用于认证 authenticators=self.get_authenticators(), # 用于分页 negotiator=self.get_content_negotiator(), # 用于解析 parser_context=parser_context )
2-4 request - 对request进行处理,getattr和setattr的处理
class Request(object): """ Wrapper allowing to enhance a standard `HttpRequest` instance. Kwargs: - request(HttpRequest). The original request instance. - parsers_classes(list/tuple). The parsers to use for parsing the request content. - authentication_classes(list/tuple). The authentications used to try authenticating the request's user. 包装器允许增强一个标准的HttpRequest实例。 Kwargs: -请求(HttpRequest)。原始请求实例。 - parsers_classes(列表/元组)。用于解析的解析器请求的内容。 = authentication_classes(列表/元组)。用于尝试的验证验证请求的用户。 """ 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 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 if self.parser_context is None: self.parser_context = {} self.parser_context['request'] = self self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET force_user = getattr(request, '_force_auth_user', None) force_token = getattr(request, '_force_auth_token', None) if force_user is not None or force_token is not None: forced_auth = ForcedAuthentication(force_user, force_token) self.authenticators = (forced_auth,)
2-4-1 __getattr__处理对DRF内request内不存在属性的请求
def __getattr__(self, attr): """ 位于request类内 实现效果:若外部调用DRF内不存在的属性,会去_request查找,_request在init内被赋予原始request If an attribute does not exist on this instance, then we also attempt to proxy it to the underlying HttpRequest object. 如果这个实例上不存在属性,那么我们也会尝试将其代理到底层HttpRequest对象。 """ try: # getattr获取self._request内attr属性的值,若找不到属性 自动返回None return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr)
2-4-2 request.data - 存储前台传输原body体内数据
@property def data(self): '''request内方法,被@property隐藏为属性使用''' if not _hasattr(self, '_full_data'): self._load_data_and_files() return self._full_data
2-4-3 request.query_params - 存储原始GET内数据
@property def query_params(self): """ More semantically correct name for request.GET. """ return self._request.GET
三、使用DRF的简单数据操作
from rest_framework.views import APIView class Books(APIView): # rest_framework.request下的Request作为参数传入 def put(self, request, pk): # django.core.handlers.wsgi.WSGIRequest----原来的djagno中的request的类 # 现在的request已经成了:rest_framework.request.Request # print(request.PUT) # 以后再取数据,直接从request.data中取 print(request.data) # 前端传过来的编码格式:json格式:{'name': '水都是', 'price': '15'} # 前端传过来的编码格式:urlencoded格式:<QueryDict: {'name': ['红楼梦'], 'price': ['15']}> # request.data是谁的对象? # request.data不同编码格式过来,它可能是不同类的对象,但是用法是一样的 # 原来的request是:request._request print(type(request._request)) # 由于__getattr__可以直接使用原有方式获取数据 # 下列二者相同,也能取出来(method,GET,POST,BODY) print(request._request.GET) print(request.GET) return JsonResponse({'status': 100, 'msg': '修改成功'})