目录
APIView
请求模块
解析模块
响应模块
渲染模块 (了解)
异常模块
APIView
APIView 继承了 View, 并重写了 as_view 方法
重写的 as_view 主体上还是 View 的 as_view, 返回的还是 view 方法
重写的 as_view 的就是 == 局部禁用了 csrf 认证 ==
- Copy# 继承了 View
- 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 的 as_view
- view = super().as_view(**initkwargs)
- view.cls = cls
- view.initkwargs = initkwargs
- # 就增加的一个功能, 就是局部禁用 crsf 认证
- return csrf_exempt(view)
APIView 继承了 View, 并重写了 dispatch 方法
- Copy"""
- 1. 在执行请求逻辑前:
- 请求模块 (二次封装 request), 解析模块 (三种数据包格式的数据解析)
- 2. 在执行请求逻辑中:
- 异常模块 (处理执行过程中的任何异常)
- 3. 在执行请求逻辑后:
- 响应模块 (二次封装 response), 渲染模块 (响应的数据能通过 JSON 和页面两种形式进行渲染)
- """
- 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
- # 1. 请求模块和解析模块: initialize_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)
- # 2. 异常模块, 捕获并处理异常: handle_exception
- except Exception as exc:
- response = self.handle_exception(exc)
- # 3. 响应模块和渲染模块: finalize_response
- self.response = self.finalize_response(request, response, *args, **kwargs)
- return self.response
请求模块
入口:
dispathch---initialize_request---Request
== 将 wsgi 的 request 对象转化为 drf 的 request 对象, 并且将 wsgi 的 request 赋值给 request._request==
drf 的 request 对象并没有 method 方法, 是通过 __getattr__反射获取的 _request.method
request.query_params
就是 _request.GET, 获取拼接参数
request.data 通过 request._full_data, 获取数据包参数
- Copyclass Request:
- """
- 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.
- """
- def __init__(self, request, parsers=None, authenticators=None,
- negotiator=None, parser_context=None):
- # drf 的 request 兼容 wsgi 的 request
- self._request = request
- Copy# drf 的 Request 类下面的__getattr__方法
- def __getattr__(self, attr):
- """
- If an attribute does not exist on this instance, then we also attempt
- to proxy it to the underlying HttpRequest object.
- """
- # drf 的 request 中没有的属性和方法, 会通过反射去 wsgi 中的 request 对象中寻找
- try:
- return getattr(self._request, attr)
- except AttributeError:
- return self.__getattribute__(attr)
- Copy# 可见, 这个 query_params 就是_request.GET
- @property
- def query_params(self):
- """
- More semantically correct name for request.GET.
- """
- return self._request.GET
- # request.data 是方法属性, 返回 request._full_data 的值
- @property
- def data(self):
- if not _hasattr(self, '_full_data'):
- self._load_data_and_files()
- return self._full_data
解析模块
入口:
dispathch---initialize_request---parsers
解析模块只处理数据包参数: form-data, urlencoded, JSON
drf 默认的解析类
- Copy# 因此我们的视图类可以自定义 parser_classes 属性, 来覆盖父类的属性
- class APIView(View):
- # APIView 的默认的解析属性
- parser_classes = api_settings.DEFAULT_PARSER_CLASSES
- 'DEFAULT_PARSER_CLASSES': [
- 'rest_framework.parsers.JSONParser',
- 'rest_framework.parsers.FormParser',
- 'rest_framework.parsers.MultiPartParser'
- ],
局部配置所有视图类的解析方式, 解析配置可以配置三种
- Copyfrom rest_framework.parsers import JSONParser, FormParser, MultiPartParser
- # drf 下的视图类继承 APIView
- class BookApiView(APIView):
- # 为当前视图类配置解析类
- parser_classes = [JSONParser, FormParser, MultiPartParser]
全局配置所有视图类的解析方式, 解析配置可以配置三种
- Copy# 在项目的 settings.py 文件中进行如下配置
- from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
- # drf 框架自定义配置
- REST_FRAMEWORK = {
- # 全局配置解析类, 适用于所有视图类
- 'DEFAULT_PARSER_CLASSES': [
- 'rest_framework.parsers.JSONParser',
- 'rest_framework.parsers.FormParser',
- 'rest_framework.parsers.MultiPartParser'
- ],
- }
配置的查找顺序: 局部 (视图类的类属性) => 全局 (settings 文件的 drf 配置) => 默认 (drf 的默认配置)
响应模块
- from rest_framework.response import Response
- Copy# data: 响应数据
- # status: 响应的网络状态码
- # -------------------------
- # template_name:drf 完成前后台不分离返回页面, 但是就不可以返回 data(不许用了解)
- # headers: 响应头, 一般不规定, 走默认
- # exception: 一般异常响应, 会将其设置成 True, 默认 False(不设置也没事)
- # content_type: 默认就是 application/JSON, 不需要处理
- 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):
- """
- Alters the init arguments slightly.
- For example, drop 'template_name', and instead use 'data'.
- Setting 'renderer' and 'media_type' will typically be deferred,
- For example being set automatically by the `APIView`.
- """
- 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
渲染模块 (了解)
Postman 请求结果是 JSON, 浏览器请求的结果是页面
同解析模块一样, render 渲染模块也可以进行局部配置和全局配置
默认配置
- Copy'DEFAULT_RENDERER_CLASSES': [
- 'rest_framework.renderers.JSONRenderer',
- 'rest_framework.renderers.BrowsableAPIRenderer',
- ],
局部配置
- Copy# views.py
- from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
- # drf 下的视图类继承 APIView
- class BookApiView(APIView):
- # 为当前视图类配置渲染类
- renderer_classes = [JSONRenderer, BrowsableAPIRenderer]
全局配置
- Copy# settings.py
- REST_FRAMEWORK = {
- # 全局配置渲染类: 适用于所有视图类
- 'DEFAULT_RENDERER_CLASSES': [
- 'rest_framework.renderers.JSONRenderer',
- 'rest_framework.renderers.BrowsableAPIRenderer', # 上线后尽量关闭
- ],
异常模块
drf 默认的异常处理模块只处理客户端请求异常
- Copy# dispatch 方法中的异常捕获
- except Exception as exc:
- response = self.handle_exception(exc)
- Copy# APIView 下面的 handle.exception 异常处理方法
- 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': 'rest_framework.views.exception_handler',
- exception_handler = self.get_exception_handler()
- # 给异常处理提供额外的参数
- context = self.get_exception_handler_context()
- response = exception_handler(exc, context) # exc: 异常对象, content: 视图对象和请求对象
- if response is None:
- self.raise_uncaught_exception(exc)
- response.exception = True
- return response
- Copy# 默认的异常处理函数只处理客户端的请求异常
- def exception_handler(exc, context):
- """
- Returns the response that should be used for any given exception.
- By default we handle the REST framework `APIException`, and also
- Django's built-in `Http404` and `PermissionDenied` exceptions.
- Any unhandled exceptions may return `None`, which will cause a 500 error
- to be raised.
- """
- if isinstance(exc, Http404):
- exc = exceptions.NotFound()
- elif isinstance(exc, PermissionDenied):
- exc = exceptions.PermissionDenied()
- if isinstance(exc, exceptions.APIException):
- headers = {}
- if getattr(exc, 'auth_header', None):
- headers['WWW-Authenticate'] = exc.auth_header
- if getattr(exc, 'wait', None):
- headers['Retry-After'] = '%d' % exc.wait
- if isinstance(exc.detail, (list, dict)):
- data = exc.detail
- else:
- data = {'detail': exc.detail}
- set_rollback()
- return Response(data, status=exc.status_code, headers=headers)
- return None
自定义异常处理方法
- Copy# 1. 在 App 文件夹下新建 exception.py 文件
- # 2. 在 exception.py 书写自定义异常处理方法
- from rest_framework.views import exception_handler as drf_exception_handler
- from rest_framework.response import Response
- def exception_handler(exc, context):
- # 主体还是 drf 默认的异常处理方法
- response = drf_exception_handler(exc, context)
- # 按照一定格式返回异常信息
- detail = f"{context.get('view')}-{context.get('request')}-{exc}"
- # 服务端错误
- if not response:
- return Response({
- 'detail': detail
- })
- else:
- response.data = {'detail': detail}
- return response
- # 3. 在项目 settings.py 文件下进行如下配置
- REST_FRAMEWORK = {
- 'EXCEPTION_HANDLER': 'api.exception.exception_handler',
来源: http://www.bubuko.com/infodetail-3358255.html