rest_framework框架的封装特点和APIView请求生命周期
rest_framework框架的封装特点:
import rest_framework from rest_framework.views import APIView from rest_framework.request import Request 在views.py中写出合适的api类,只需要继承rest_framework中generics中的某个类,重写我们需要的方法实现合适的逻辑即可
APIView请求生命周期
""" APIView的as_view(局部禁用csrf) =>走父级的as_view调用dispatch分发请求 =>APIView自己重写了dispatch,使用自己完成分发 =>分发前完成request二次封装、数据解析 =>三大认证 =>请求的实际响应(自己的视图类的处理分发) =>出现了异常,就会交给异常模块处理异常 =>响应模块完成响应、渲染模块可以以json或浏览器两种方式渲染 APIView请求生命周期 1)APIView类继承View类,重写了as_view和dispatch方法 2)重写的as_view方法,主体还是View的as_view,只是在返回视图view函数地址时,局部禁用csrf认证 3)在执行请求逻辑前:请求模块(二次封装request)、解析模块(三种数据包格式的数据解析) 在执行请求逻辑中:异常模块(执行出任何异常交给异常模块处理) 在执行请求逻辑后:响应模块(二次封装response)、渲染模块(响应的数据能JSON和页面两种渲染) """
生命周期图:
请求模块
""" request._request 被request完全兼容 request.query_params | request.data 1)将wsgi的request对象转化成drf的Request类的对象 2)封装后的request对象完全兼容wsgi的request对象,并且将原request保存在新的request._request 3)重写格式化请求数据存放位置 拼接参数:request.query_params 数据包参数:request.data 源码解析: 入口:APIVIew的dispatch方法的request=self.initialize_request(request,*args,**kwargs) print(request._request.method) 在内部将wsgi的request赋值给request._request print(request.method) 就是通过__getattr__走的是request._request.method print(request.query_params) 走的是方法属性,就是给request._request.GET重新命名 print(request.data) 走的是方法属性,值依赖于request._full_data """
解析模块
""" 解析模块:只处理数据包参数 -form-data,urlencoded,json 局部配置:parser_classes = [JSONParser, FormParser, MultiPartParser] 全局配置: 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ], 1)全局配置所有视图类的解析方式,解析配置可以配置三种 2)局部配置当前视图类的解析方式,解析配置可以配置三种 3)配置的查找顺序:局部(视图类的类属性) =>全局(settings文件的drf配置)=>默认(drf的默认配置) 注:该模块了解,但是全局局部配置是重点 REST_FAMEWORK = { 全局配置解析类:适用于所有视图类 'DEFAULT_PARSER_CLASSES': [ #'rest_framework.parsers.JSONParser', #'rest_framework.parsers.FormParser', #'rest_framework.parsers.MultiPartParser' ], } 源码解析: 入口:APIVIew的dispatch方法的 request=self.initialize_request(request,*args,**kwargs) 获取解析类:parsers = self.get_parsers(), 进行局部全局默认配置查找顺序进行查找:return [parser() for parser in self.parser_classes] """
响应模块
""" Response(data=常量|列表|字典,status=网络状态码) data:响应数据 status:响应的网络状态码 template_name:drf完成前后台不分离返回页面,但是就不可以返回data(不需要了解) headers:响应头,一般不规定,走默认 exception:一般异常响应,会将其设置成True,默认False(不设置也没事) content_type:默认就是 application/json,不需要处理 """
渲染模块
""" 局部配置:renderer_classes = [JSONRenderer, BrowsableAPIRenderer] 全局配置: 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', # 上线后尽量关闭 ], 渲染模块(了解):Postman请求结果是json,浏览器请求结果是页面 可以全局与局部配置 局部配置解析类:只适用于当前视图类 parser_classes = [JSONParser, FormParser, MultiPartParser] 局部配置渲染类:只适用于当前视图类 renderer_classes = [JSONRenderer, BrowsableAPIRenderer] def post(self, request, *args, **kwargs): print(request._request.method) # 在内部将wsgi的request赋值给request._request print(request.method) # 就是通过__getattr__走的是request._request.method print(request.query_params) # 走的是方法属性,就是给request._request.GET重新命名 print(request.data) # 走的是方法属性,值依赖于request._full_data return Response({ 'msg': 'apiview post ok' }) """
异常模块
""" settings中配置:'EXCEPTION_HANDLER': 'api.exception.exception_handler', 重写exception_handler方法: 一定要在settings文件中将异常模块配置自己的异常处理函数 from rest_framework.views import exception_handler as drf_exception_handler from rest_framework.response import Response 先交个drf处理客户端异常,如果结果response代表服务器异常,自己处理 最终一定要在日志文件中记录异常现象 def exception_handler(exc, context): response = drf_exception_handler(exc, context) detail = '%s - %s - %s' % (context.get('view'), context.get('request').method, exc) if not response: # 服务端错误 response = Response({'detail': detail}) else: response.data = {'detail': detail} 核心:要将response.data.get('datail')信息记录到日志文件 logger.waringz(response.data.get('datail')) return response 源码解析: 入口:APIVIew的handle_exception方法的 获取异常函数:exception_handler = self.get_exception_handler() 提供额外参数:context = self.get_exception_handler_context() 默认的exception_handler函数只处理客户端异常形成的response对象, 服务器异常不做处理 二次封装过后的response,处理了结果渲染 """
原生的Django与drf比较:drf不受csrf认证限制
from django.views import View from django.http import JsonResponse class BookView(View): def get(self, request, *args, **kwargs): return JsonResponse({ 'msg': 'view get ok' }) def post(self, request, *args, **kwargs): return JsonResponse({ 'msg': 'view post ok' }) ----------------------------------------------- from rest_framework.views import APIView from rest_framework.response import Response class BookAPIView(APIView): def get(self, request, *args, **kwargs): return Response({ 'msg': 'apiview get ok' }) def post(self, request, *args, **kwargs): return Response({ 'msg': 'apiview post ok' }) settings文件中一定要注册drf INSTALLED_APPS = [ 'rest_framework', ] # drf框架自定义配置 REST_FAMEWORK = { # 全局配置解析类:适用于所有视图类 'DEFAULT_PARSER_CLASSES': [ #'rest_framework.parsers.JSONParser', #'rest_framework.parsers.FormParser', #'rest_framework.parsers.MultiPartParser' ], # 全局配置渲染类:适用于所有视图类 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', #'rest_framework.renderers.BrowsableAPIRenderer', 上线尽量关闭 ], # 异常模块:异常处理函数 # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', 'EXCEPTION_HANDLER': 'api.exception.exception_handler', } # 在api文件夹中新建exception文件 # 一定要在settings文件中将异常模块配置自己的异常处理函数 from rest_framework.views import exception_handler as drf_exception_handler from rest-framework.response import Rseponse def exception_handler(exc, context): response = drf_exception_handler(exc, context) detail = '%s - %s - %s' % (context.get('view'), context.get('request').method, exc) if not response: 服务器错误 response = Rseponse({'detail':detail}) else: response.data = {'detail':detail} # 核心:要将response.data.get('detail')信息记录到日志中 logger.waring(response.data.get('detail')) return response # utils文件夹下的views.py文件 def handle_exception(self,exc): """ Handle any exception that occurs, by returning an appropriate response, or re-raising the error. # 处理任何发生的异常,通过返回适当的响应, # 或重新引发错误。 """ # 出现三大认证相关异常,额外处理一下响应头 if isinstance(exc, (exceptions.NotAuthenticated, exceptions.AuthenticationFailed)): # WWW-Authenticate header for 401 responses, else coerce to 403 auth_header = self.get_authenticate_header(self.request) if auth_header: exc.auth_header = auth_header else: exc.status_code = status.HTTP_403_FORBIDDEN # 获取出来异常的函数:该文件独立存在的exception_handler函数 exception_handler = self.get_exception_handler() # 给异常处理提供额外的参数 context = self.get_exception_handler_context() # exc异常对象,context中用视图对象和请求对象 response = exception_handler(exc,context) # 默认的exception_handler函数只处理客户端异常形成response对象,服务器异常不做处理,返回None if response is None: self.raise_uncaught_exception(exc) response.exception = True return response 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: # 三大认证(认证、权限、频率),用来替换csrf安全认证,要比csrf认证强大得多 # 异常模块 -处理请求异常分支的 response = self.handle_exception(exc) # 二次封装response,处理了结果渲染 self.response = self.finalize_response(request, response, *args, **kwargs) return self.response status文件中可以自定义网络状态码