rest_framework框架的封装特点

# 导入 rest_framework
# rest_framework的导入风格就是按照英文的意思就可以了。
import rest_framework
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.exceptions import APIException
from rest_framework.pagination import PageNumberPagination
from rest_framework.settings import APISettings
from rest_framework.parsers import JSONParser
from rest_framework.filters import OrderingFilter

原生Django与DRF比较

原生Django

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'
})

drf

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'
})

django的配置文件中的CSRF认证注释去掉。

测试原生的Django接口和DRF接口发现:

原生Django接口提交post请求会被django拒绝

用DRF写的接口不会被拒

我们只有看了源码才知道,是因为DRF接口继承了APIView,内部重写了原生View类,并添加了新功能:局部禁用csrf

view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
# 局部禁用csrf
return csrf_exempt(view)

APIView 的请求生命周期

  • APIView 类继承View类,重写了as_view和dispatch方法

  • APIView类重写的as_view()方法本质上还是View的as_view,只是在返回视图view函数地址时,局部禁用了csrf认证

  • APIView中重写dispatch方法:

    • 在执行请求逻辑前,执行请求模块(二次封装request对象),解析模块(三种数据包格式的数据解析)
    • 在执行请求逻辑中,执行逻辑,若出现异常交给异常模块处理
    • 在执行请求逻辑后,执行响应模块(二次封装response)、渲染模块(响应的数据能够使用JSON和页面两种方式渲染)

请求模块(request)

  • 将wsgi的request对象二次封装,转换成drf的Request类的对象

  • drf封装后的request对象完全兼容wsgi的request对象,并且保存原request对象在新request._request方法中:

    new_request.__dict__ = request.__dict
    new_request._request = request
  • 重新格式化请求数据存放位置

    拼接参数:request.query_params

    数据包参数:request.data

源码分析:
1. 入口:APIVIew的dispatch方法的 request=self.initialize_request(request, *args, **kwargs)
2. print(request._request.method) # 在内部将wsgi的request赋值给request._request
3. print(request.method) # 就是通过__getattr__走的是request._request.method
4. print(request.query_params) # 走的是方法属性,就是给request._request.GET重新命名
5. print(request.data) # 走的是方法属性,值依赖于request._full_data

解析模块(parser_classes)

只处理请求的数据包参数(request.data)

  • form-data
  • urlencoded
  • application/json

可以针对全局配置、局部配置 方式

全局配置,在项目settings配置文件中配置

# drf框架自定义配置,不需要哪个把哪个注释掉就可以了。
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
} 局部配置,在视图类中实现:
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
class BookAPIView(APIView):
parser_classes = [JSONParser, FormParser, MultiPartParser] 配置好之后解析模块的查找顺序:
局部(视图类中)->全局(settings配置文件中)->drf默认配置(APIView中) 源码分析: 1. 入口:APIVIew的dispatch方法的 request=self.initialize_request(request, *args, **kwargs)
2. 获取解析类:parsers=self.get_parsers(),
3. 进行局部全局默认配置查找顺序进行查找:return [parser() for parser in self.parser_classes] 源码:
class APIView(View):
# The following policies may be set at either globally, or per-view.
parser_classes = api_settings.DEFAULT_PARSER_CLASSES def get_parsers(self):
"""
Instantiates and returns the list of parsers that this view can use.
"""
return [parser() for parser in self.parser_classes]

异常模块(exception_handler)

异常模块就是在客户端或者服务端请求的时候出现异常了采取的措施:

我们可以重写捕获异常的方法:

源码分析:
1. 入口:APIVIew的dispatch方法:
except Exception as exc: # 遇到异常捕获异常
response = self.handle_exception(exc) 2. 执行handle_exception方法:
exception_handler = self.get_exception_handler()
得到django中提供的异常模块处理方法; context = self.get_exception_handler_context()
生成一个大字典,包含类名称,请求参数,不变长参数等等 response = exception_handler(exc, context)
执行函数,传入大字典响应给客户端 这里我们看了源码知道了django中的异常捕获是通过一个函数方法实现,我们也可以自定义我们的异常处理信息:
在settings中配置:
REST_FRAMEWORK = {
# 异常模块处理
# 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', django中提供的
'EXCEPTION_HANDLER': 'api.exception.exception_handler',
} 在api的新建一个exception py文件,文件内写入:
# 一定要在settings文件中将异常模块配置自己的异常处理函数
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import 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('detail')信息记录到日志文件
# logger.waring(response.data.get('detail')) return response 通过我们自定义的一个异常处理方法最终其他人在用我们的接口的时候,如果接口错误会返回以下信息,而不会返回一些乱七八糟的页面了。
{
"detail": "<api.views.CarAPIView object at 0x000000000D2C6320> - PUT - 方法 “PUT” 不被允许。"
}

响应模块(Response)

Response,可以对响应的数据指定参数:

  • data:响应的数据(data=)
  • status:网络的状态码(status=)
  • template_name:drf前后台不分离的情况下返回的页面
  • headers:响应头,一般不写,走默认的
  • exception:异常响应,默认为False
  • content_type:默认是application/json的数据格式
from rest_framework.views import APIView
from rest_framework.response import Response class CarAPIView(APIView):
def get(self,request,*args,**kwargs):
print(request.method)
print(request._request.method)
return Response(data={"msg":"apiview get ok"},status=200)

渲染模块(render)

可以做全局配置或局部配置,主要针对客户端返回的数据格式做限制

postman测试工具返回的是json,浏览器请求到的结果是一个页面

from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
# 局部渲染
renderer_classes = [JSONRenderer, BrowsableAPIRenderer] # 全局渲染配置
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer', # 项目真正上线的时候会把它注释掉,因为浏览器访问接口是一个页面
],
}

二次封装Response类

(自定义一个APIResponse类继承Response),优化响应

正确的:APIResponse('results'=[]) # 数据状态码和状态信息有默认值,可以不传

异常的:Response(1,'error', status=400) # 可以按位传数据状态码和状态信息,错误时还可以设置网络状态码

封装后的响应与封装前的响应结果一致,但是大大简化了响应写法:

class APIResponse(Response):
# 重写的APIResponse类是继承了restframework中的Response 再此基础上重写多个初始化值
# 设置默认参数
def __init__(self, data_status=0, data_msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs):
data = {
'status': data_status,
'msg': data_msg,
}
# results可能是False、0等数据,这些数据某些情况下也会作为合法数据返回
if results is not None:
data['results'] = results
data.update(kwargs)
# 继承并重用父类的 的init方法,把自定义的data数据体传进去
# 父类的:__init__(self, data=None, status=None,template_name=None, headers=None,exception=False, content_type=None):
# 异常响应,默认为False
super().__init__(data=data, status=http_status, headers=headers, exception=exception) class CarAPIView(APIView):
def get(self,request,*args,**kwargs):
print(request.query_params)
print(request.data)
# print(request.method)
# print(request._request.method)
return APIResponse(data={"msg":"apiview get ok"})

DRF 请求生命周期以及各模块解析的更多相关文章

  1. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  2. drf复习(一)--原生djangoCBV请求生命周期源码分析、drf自定义配置文件、drf请求生命周期dispatch源码分析

    admin后台注册model  一.原生djangoCBV请求生命周期源码分析 原生view的源码路径(django/views/generic/base.py) 1.从urls.py中as_view ...

  3. Django(47)drf请求生命周期分析

    前言   一般我们写完序列化以后,我们就会开始写视图了,drf中我们一般使用CBV的方式,也就是类视图的方式,最基础的我们会使用from rest_framework.views import API ...

  4. 3) drf 框架生命周期 请求模块 渲染模块 解析模块 自定义异常模块 响应模块(以及二次封装)

    一.DRF框架 1.安装 pip3 install djangorestframework 2.drf框架规矩的封装风格 按功能封装,drf下按不同功能不同文件,使用不同功能导入不同文件 from r ...

  5. drf框架概况-resful接口规范-请求模块-渲染模块-Postman-drf请求生命周期

    drf框架 全称:django-rest- framework 知识点: """ 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码-基于restful ...

  6. Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)

    一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...

  7. Django中间件-跨站请求伪造-django请求生命周期-Auth模块-seettings实现可插拔配置(设计思想)

    Django中间件 一.什么是中间件 django中间件就是类似于django的保安;请求来的时候需要先经过中间件,才能到达django后端(url,views,models,templates), ...

  8. APIview的请求生命周期源码分析

    目录 APIview的请求生命周期源码分析 请求模块 解析模块 全局配置解析器 局部配置解析器 响应模块 异常处理模块 重写异常处理函数 渲染模块 APIview的请求生命周期源码分析 Django项 ...

  9. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(二)

    ASP.NET 请求生命周期 全局应用类也可以用来跟踪每个独立请求的生命周期,包括请求从 ASP.NET 平台传递到 MVC 框架.ASP.NET 框架会创建一个定义在 Global.asax 文件中 ...

随机推荐

  1. 使用Pyppeteer进行gmail模拟登录

    import asyncio import time from pyppeteer import launch async def gmailLogin(username, password, url ...

  2. uoj118 【UR #8】赴京赶考

    题目 不难发现我们直接走过去就行了 考虑到第\(i\)行的构造方法就是把\(b\)数组作为模板,每个数和\(a_i\)异或一下就可以了 于是不难发现对于一段连续相等的\(a\),它们在矩阵上就形成了完 ...

  3. HDU 4325 离散化+树状数组 或者 不使用树状数组

    题意:给出一些花的开放时间段,然后询问某个时间点有几朵花正在开放. 由于ti<1e9,我们需要先将时间离散化,然后将时间点抽象为一个数组中的点,显然,我们需要进行区间更新和单点查询,可以考虑线段 ...

  4. LeetCode 67. Add Binary【个位补0,不必对齐】【easy】

    Given two binary strings, return their sum (also a binary string). The input strings are both non-em ...

  5. [笔记]Android开发环境配置及HelloWorld程序

    Android的开发须要下面四个工具: 1.JDK 2.Eclipse 3.Android SDK 4.ADT   具体功能: 1.JDK.JDK即Java Development Kit(Java开 ...

  6. linux格式化磁盘

    linux格式化磁盘 查看系统磁盘情况 [root@db02 ~]# fdisk -l #查看当前系统上所有存储设备(包括挂在和没挂载的)  注:如果没有管理员权限是看不见磁盘的,因为fdisk默认读 ...

  7. 基于第三方开源库的OPC服务器开发指南(2)——LightOPC的编译及部署

    前文已经说过,OPC基于微软的DCOM技术,所以开发OPC服务器我们要做的事情就是开发一个基于DCOM的EXE文件.一个代理/存根文件,然后就是写一个OPC客户端测试一下我们的服务器了.对于第一项工作 ...

  8. java——有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

    package java_day10; /* * 有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? */ public class Demo04 { public stat ...

  9. Perl 数组

    Perl 数组 Perl 数组一个是存储标量值的列表变量,变量可以是不同类型. 数组变量以 @ 开头.访问数组元素使用 $ + 变量名称 + [索引值] 格式来读取,实例如下: 实例 #!/usr/b ...

  10. thinkphp 自动加载

    在3.2中,基本上无需手动加载类库文件,你可以很方便的完成自动加载. 命名空间自动加载 系统可以通过类的命名空间自动定位到类库文件,例如: 我们定义了一个类 Org\Util\Auth 类: name ...