DRF 请求生命周期以及各模块解析
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 请求生命周期以及各模块解析的更多相关文章
- DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
- drf复习(一)--原生djangoCBV请求生命周期源码分析、drf自定义配置文件、drf请求生命周期dispatch源码分析
admin后台注册model 一.原生djangoCBV请求生命周期源码分析 原生view的源码路径(django/views/generic/base.py) 1.从urls.py中as_view ...
- Django(47)drf请求生命周期分析
前言 一般我们写完序列化以后,我们就会开始写视图了,drf中我们一般使用CBV的方式,也就是类视图的方式,最基础的我们会使用from rest_framework.views import API ...
- 3) drf 框架生命周期 请求模块 渲染模块 解析模块 自定义异常模块 响应模块(以及二次封装)
一.DRF框架 1.安装 pip3 install djangorestframework 2.drf框架规矩的封装风格 按功能封装,drf下按不同功能不同文件,使用不同功能导入不同文件 from r ...
- drf框架概况-resful接口规范-请求模块-渲染模块-Postman-drf请求生命周期
drf框架 全称:django-rest- framework 知识点: """ 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码-基于restful ...
- Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)
一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...
- Django中间件-跨站请求伪造-django请求生命周期-Auth模块-seettings实现可插拔配置(设计思想)
Django中间件 一.什么是中间件 django中间件就是类似于django的保安;请求来的时候需要先经过中间件,才能到达django后端(url,views,models,templates), ...
- APIview的请求生命周期源码分析
目录 APIview的请求生命周期源码分析 请求模块 解析模块 全局配置解析器 局部配置解析器 响应模块 异常处理模块 重写异常处理函数 渲染模块 APIview的请求生命周期源码分析 Django项 ...
- [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(二)
ASP.NET 请求生命周期 全局应用类也可以用来跟踪每个独立请求的生命周期,包括请求从 ASP.NET 平台传递到 MVC 框架.ASP.NET 框架会创建一个定义在 Global.asax 文件中 ...
随机推荐
- 基于Netty的RPC架构学习笔记(二):netty服务器
文章目录 简介 Netty服务端Hello World案例 举个
- Tesseract&tesseractOCRiOS
安装tesseract在上篇. 1.安装之后默认语言包只有英文包,在github上下载中文简体,链接:https://github.com/tesseract-ocr/tessdata 然后放入tes ...
- foreach循环的简单写法
简单的foreach循环写法: pickedItems.ForEach(item => { this.List.Remove(item); }); //注意,List 必须和pickedItem ...
- [JZOJ6271] 2019.8.4【NOIP提高组A】锻造
题目 题目大意 武器的每个级别有固定的两种属性\(b_i\)和\(c_i\) 可以用\(a\)的代价得到一把\(0\)级的武器. 可以将\(x\)级武器和\(y=\max(x-1,0)\)级武器融合锻 ...
- python实现百度OCR图片识别
一.直接上代码 import base64 import requests class CodeDemo: def __init__(self,AK,SK,code_url,img_path): se ...
- 自定义Collection View布局
转自answer-huang的博客 原文出自:Custom Collection View Layouts UICollectionView在iOS6中第一次被介绍,也是UIKit视图类中的一颗 ...
- JAVA 设计模式之 原型模式详解
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式利用的是克隆的原理,创建新的对象,JDK提供的Cloneable 和JSON. ...
- csdn自动生成目录索引、插入代码片快捷键
文章目录 自动生成目录索引 插入代码片 自动生成目录索引 文章开头加入 @[TOC](目录描述) 目录描述可不写 插入代码片 cmd/ctrl + shift + k
- ASP.NET的底层体系2
文章引导 1.ASP.NET的底层体系1 2.ASP.NET的底层体系2 引言 接着上一篇ASP.NET的底层体系1我们继续往下走 一.System.Web.HttpRuntime.ProcessRe ...
- Python 函数与内置函数
1.函数的基本定义 def 函数名称(参数) 执行语句 return 返回值 def : 定义函数的关键字: 函数名称:顾名思义,就是函数的名字,可以用来调用函数,不能使用关键字来命名,做好是用这个函 ...