DRF框架介绍
安装
pip install djangorestframework
DRF框架规范的封装风格
# 视图: from rest_framework.views import APIView # 响应: from rest_framework.response import Responses # 请求: from rest_framework.request import Request # 序列化: from rest_framework.serializers import Serializer # 配置: from rest_framework.settings import APISettings # 过滤器: from rest_framework.filters import SearchFilter # 分页: from rest_framework.pagination import PageNumberPagination # 认证: from rest_framework.authentication import TokenAuthentication # 认证: from rest_framework.permissions import IsAuthenticated # 认证: from rest_framework.throttling import SimpleRateThrottle from rest_framework.views import APIView class Test(APIView): def get(self, request, *args, **kwargs): return Response('drf get ok')
DRF请求生命周期
1) 请求走的是APIView的as_view函数 2) 在APIView的as_view调用父类(django原生)的as_view, 还禁用了csrf认证 3) 在父类的as_view中dispatch方法请求走的又是APIView的dispatch 4) 完成任务方法交给视图类的请求函数处理, 得到请求的响应结果, 返回给前台
APIView(as_view())禁用csrf => View(as_view()) => APIView(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 = 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
dispatch的请求模块: request对象
APIView类中的dispatch方法中: request = self.initialize_request(request, *args, **kwargs)
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 = self.initialize_request(request, *args, **kwargs) ... def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context )
1) drf对原始request做了二次封装, request._request就是原生的request
2) 原生request对象的属性和方法都可以被drf的request对象直接访问(兼容)
3) drf请求的所有url拼接参数均被解析到query_params中, 所有数据包都被解析到data中
query_params和data的使用
class Test(APIView): def get(self, request, *args, **kwargs): # url拼接的参数 print(request._request.GET) # 二次封装方式 print(request.GET) # 兼容 print(request.query_params) # 扩展 return Response('drf get ok') def post(self, request, *args, **kwargs): # 所有请求方式携带的数据包 print(request._request.POST) # 二次封装方式 print(request.POST) # 兼容 print(request.data) # 扩展, 兼容性最强, 三种数据方式都可以 print(request.query_params) return Response('drf post ok')
dispatch的渲染模块: 浏览器和Postman请求结果渲染数据的方式不一样
APIView类中的dispatch方法中:self.response = self.finalize_response(request, response, *args, **kwargs)
1) # 渲染response入口 self.response = self.finalize_response(request, response, *args, **kwargs) 2) # 获取渲染模板的方法 neg = self.perform_content_negotiation(request, force=True) 3) # 获取渲染类 renderers = self.get_renderers() 4) # 获取settings中配置的模板信息 def get_renderers(self): return [renderer() for renderer in self.renderer_classes] 5) # setting中的配置信息 # 自定义drf配置 REST_FRAMEWORK = { # drf提供的渲染类 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.TemplateHTMLRenderer', ], }
# 全局配置: settings文件中 REST_FRAMEWORK = { # drf提供的渲染类 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], } # 局部配置: 类视图中定义类属性 renderer_classes = [JSONRenderer]
DRF的APIView查找渲染类配置的路径
自定义视图类 => APIView视图类 => 自定义DRF配置 => DRF默认配置
dispatch的解析模块
APIView类中的dispatch方法中: request = self.initialize_request(request, *args, **kwargs)
1) # 请求解析模块入口 request = self.initialize_request(request, *args, **kwargs) 2) # 获取解析类 parsers=self.get_parsers() 3) # 获取settings中的parser配置信息 def get_parsers(self): return [parser() for parser in self.parser_classes] 4) # settings中的parser配置信息 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ],
全局配置与局部配置解析类
# 全局配置: settings文件中 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ] # 局部配置: 类视图中定义类属性 parser_classes = [JSONParser]
DRF的APIView查找解析类配置的路径
自定义视图类 => APIView视图类 => 自定义DRF配置 => DRF默认配置
dispatch的异常处理模块
APIView类中的dispatch方法中: response = self.handle_exception(exc)
1) # 异常处理模块入口 response = self.handle_exception(exc) 2) # 获取处理异常的句柄(方法) exception_handler = self.get_exception_handler() 3) # 异常处理的结果 response = exception_handler(exc, context) 4) # 没有异常内容抛出异常信息 if response is None: self.raise_uncaught_exception(exc) 5) # 有异常内容, 返回异常内容 return response
为什么要自定义异常模块
所有经过drf的APIView的视图类产生的异常, 都可以提供异常处理方案
drf默认提供了异常处理方案(rest_framework.views.exception_heandler), 但是处理范围有限
drf提供的处理方案, 处理了的返回异常信息, 每处理的返回None(后续就是服务器抛异常给前台)
自定义异常的目的就是解决drf没有处理的异常, 让前台得到合理的异常信息, 后台记录异常具体信息
自定义异常处理类的方案: 自定义exception_handler函数如何书写实体
1) 现将异常处理交给rest_framework.views的exception_handler去处理
2) 判断处理的结果(返回值)response, 有值代表drf已经处理, None代表需要自己去处理
# 自定义异常就是提供exception_handler异常处理函数, 处理的目的就是让response一定有值 # 1. 在app中创建exception.py文件 # 2. 在exception.py文件中导入drf中异常处理方法exception_handler from rest_framework.views import exception_handler as drf_exception_handler # 3. 自定义异常处理函数 def exception_handler(exc, context): # 使用drf的exception_handler()方法得到response response = drf_exception_handler(exc, context) # 如果response为None, 我们就给他赋值(达到异常处理的目的) if not response: # print(exc) # print(context) print('%s - %s - %s' % (context['view'].__class__, context['request'].method, exc)) return Response({ 'detail': '服务器错误' }) # 如果response有值, 则直接返回response对象 return response # 4. 在项目的settings文件中导入自定义的drf异常处理模块 'EXCEPTION_HANDLER': 'apiTwo.exception.exception_handler'
响应处理模块
from http.client import responses from django.template.response import SimpleTemplateResponse from rest_framework.serializers import Serializer class Response(SimpleTemplateResponse): def __init__(self, data=None, status=None, template_name=None, headers=None, exception=False, content_type=None): super().__init__(None, status=status) if isinstance(data, Serializer): msg = ( 'You passed a Serializer instance as data, but ' 'probably meant to pass serialized `.data` or ' '`.error`. representation.' ) raise AssertionError(msg) self.data = data self.template_name = template_name self.exception = exception self.content_type = content_type if headers: for name, value in headers.items(): self[name] = value @property def rendered_content(self): renderer = getattr(self, 'accepted_renderer', None) accepted_media_type = getattr(self, 'accepted_media_type', None) context = getattr(self, 'renderer_context', None) assert renderer, ".accepted_renderer not set on Response" assert accepted_media_type, ".accepted_media_type not set on Response" assert context is not None, ".renderer_context not set on Response" context['response'] = self media_type = renderer.media_type charset = renderer.charset content_type = self.content_type if content_type is None and charset is not None: content_type = "{}; charset={}".format(media_type, charset) elif content_type is None: content_type = media_type self['Content-Type'] = content_type ret = renderer.render(self.data, accepted_media_type, context) if isinstance(ret, str): assert charset, ( 'renderer returned unicode, and did not specify ' 'a charset value.' ) return ret.encode(charset) if not ret: del self['Content-Type'] return ret @property def status_text(self): return responses.get(self.status_code, '') def __getstate__(self): state = super().__getstate__() for key in ( 'accepted_renderer', 'renderer_context', 'resolver_match', 'client', 'request', 'json', 'wsgi_request' ): if key in state: del state[key] state['_closable_objects'] = [] return state
响应构造器
def __init__(self, data=None, status=None, template_name=None, headers=None, exception=False, content_type=None): """ Args: data: 响应数据 status: http响应状态码 template_name: drf也可以渲染页面, 渲染的页面模板地址(不用了解) headers: 响应头 exception: 是否异常 content_type: 响应的数据格式(一般不用处理, 响应头中带有, 且默认是json) """
常规实例化响应对象
from rest_framework import status return Response(data={数据}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True, headers={设置的响应头})