drf知识点总结、请求与响应、视图组件
drf的整体知识点
前后端开发模式
API接口、postman使用、序列化和反序列化、restful规范
drf就是django的第三方app,能够快速实现符合restful规范的接口
cbv的执行流程:
路由匹配成功后,执行对应的视图类(视图类.as_view()),也就是执行View的as_view方法里面的闭包函数view,返回了self.dispatch(request,*args,**kwargs)方法
View中dispatch方法:根据请求的方式,执行视图函数中以请求方式命名的方法
反射
通过字符串动态的获取,设置,判断,对象中的属性或方法
getattr: res=getattr(self,'run',None)
setattr: setattr(self,'speak',内存地址) self.speak()
hasattr: hasattr(self,'run')
APIView
继承了View,执行流程
1. APIView的as_view调用了父类的as_view,返回了不需要csrf认证的view
2. 请求来了,执行View的as_view的闭包view,执行了APIView中的dispatch方法
3. APIView中的dispatch
* 1. 包装了新的request
* 2. 在执行视图函数之前:执行了三大认证
* 3. 执行了视图函数:请求方式是什么,就执行视图函数中的什么方法
* 4. 全局异常捕获:全局异常,统一返回格式
序列化类
Serializer、ModelSerializer、序列化、反序列化、校验
请求与响应
Request类:属性和方法、Response类
视图层
2基类、5个扩展类、9个子类、视图集
路由的使用
认证,频率,权限
过滤、排序、分页
全局异常处理
接口文档:自定生成,自己写
前后端分离:jwt认证方式,登录
公式内部:RBAC
django:admin 美化
drf之请求与响应
Request和Response类
继承APIView后,请求对象request中,每一次请求都是一个新的request
Request类
REST framework传入视图的request对象不再是django默认的HttpResquest对象,而是REST framework提供的扩展了HttpResquest类的Request类的对象。
REST framework提供了Parser解析器,在接收到请求后会自动根据Content-Type,指名的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
data
request.data返回解析之后的请求体数据。类似于django中标准的request.POST和request.FILES属性,但提供如下特性:
- 包含了解析之后的文件和非文件数据
- 包含了对POST、PUT、PATCH请求方式解析的数据
- 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
注意:put提交的数据在request.POST中取不到的
query_params
与django标准的request.GET
相同,只是更换了更正确的名称而已。
其他的用起来跟之前一样用(FILES,method,path...), 底层实现原理就是:__getattr__
Response类
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
REST framework提供了Renderer渲染器,用来根据请求头中的Accept(接受数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置文件修改相应格式。
配置
可以在rest_framework.settings查找所有的drf默认配置项
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
'rest_framework.renderers.JSONRenderer', # json渲染器
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器
)
}
构造方式
Response(data,status=None,template_name=None,headers=None,content_type=None)
data数据不要时render处理之后的数据,只需要传递python的内建数据类型即可,restframework会使用renderer渲染器处理data
data不能是复杂结构的数据,如django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了python字典类型)在传递给data参数。
参数说明
- data:为响应准备的序列化处理后的数据,也就是序列化成的json格式字符串。放在响应的body中了。
- status:状态码,默认为200,drf把所有的http响应状态码都做成了常量,可以直接导进来用
- template_name:模版名称,如果使用HTMLRenderer时需指名
- headers:用于存放响应头信息的字典:
headers={'name':'Jason'}
- content_type:响应数据的Content_Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
原生django中在响应头中加数据:4个响应都可以这样写
res=JsonResponse(d)
res['rrr']='yyy'
return res
常用属性
- data:传给response对象的序列化后,但尚未render处理的数据。
- status_code:状态码的数字
- content:经过render处理后的响应数据
状态码
为了方便设置状态码,REST framework在rest_framework.status
模块中提供了常用状态码常量
drf能够解析的请求编码,响应编码
能够解析的请求编码
- urlencoded
- form-data
- json
项目中没有配置,是因为在drf内置的配置文件中提前配好了
drf也是有两套,一套是项目中的配置(settings.py),一套是默认的配置
drf的配置文件settings.py中有DEFAULT_PARSER_CLASSES(默认的解析类)
'rest_framework.parsers.JSONParser' 可以解析json格式
'rest_framework.parsers.FormParser' 可以解析urlencoded格式
'rest_framework.parsers.MultiPartParser' 可以解析form-data格式
指定接口的能够解析的请求编码格式
方式1:全局配置,到项目配置文件。以后所有的接口都遵循这个配置
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser', # 不支持form-data格式
],
}
配置了指定的请求编码,那么在配置文件中的请求编码就无法通过解析了。
方式2:局部配置
class Books(GenericAPIView):
parser_classes = [JSONParser] # 在视图类中指定json格式编码格式,后续配置文件,drf配置文件的设置都失效
总结
解析类的使用顺序:优先用视图类自己的,然后用项目配置文件,最后用内置的
实际项目中如何配置
基本上都运行JSONParser,FormParser
如果上传文件只允许MultiPartParser
能够解析的响应编码
浏览器的好看的样式,postman看到json格式
默认情况下,响应的编码是根据客户端类型决定的
全局配置:在项目的配置文件
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
# 'rest_framework.renderers.JSONRenderer', # json格式
'rest_framework.renderers.BrowsableAPIRenderer', #浏览器的格式
]
}
局部配置
class TestView(APIView):
renderer_classes = [JSONRenderer,]
在实际编码中,响应一般不配,就应默认
drf之视图组件
由于drf提供了一个顶层的视图类APIView,我们可以通过继承APIView写视图类
后期我们要写的代码可能重复代码比较多,就可以使用面向对象的继承,封装
2个视图基类
- APIView
- GenericAPIView(继承了APIView)
类属性
queryset=User.objects
# 如果是queryset对象也可以写User.objects.all(),源码
if isinstance(queryset, QuerySet):
queryset = queryset.all()
serializer_class=UserSerializer:指定要序列化类
方法
self.get_object() # 根据pk获取单个数据,还是要在请求方法里面带指定的参数,GenericAPIView视图类会通过此参数过滤出数据
self.get_serializer # 获取要使用的序列化类
self.get_serializer(instance=Book,data=request.data) # 获取所有要序列化数据,也可以用另一种写法
self.get_serializer_class()(instance=Book,data=request.data)
基于APIView写5个接口
class Books(APIView):
def get(self,request):
res=Book.objects.all()
ser=BookSerializer(instance=res,many=True)
return Response(ser.data)
def post(self,request):
ser=BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'},status=201)
else:
return Response(ser.errors)
class BookDetail(APIView):
def get(self,request,pk):
res=Book.objects.filter(pk=pk).first()
ser=BookSerializer(instance=res)
return Response(ser.data)
def put(self, request, pk):
res = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=res, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功'}, status=201)
else:
return Response(ser.errors)
def delete(self,request,pk):
Book.objects.filter(pk=pk).delete()
return Response('')
基于GenericAPIView写5个接口
class Books(GenericAPIView):
queryset = Book.objects
serializer_class = BookSerializer
def get(self,request):
# 获取当前数据对象
res=self.get_queryset()
ser=self.get_serializer(instance=res,many=True)
return Response(ser.data)
def post(self,request):
ser=self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'},status=201)
else:
return Response(ser.errors)
class BookDetail(GenericAPIView):
queryset = Book.objects
serializer_class = BookSerializer
def get(self,request,pk):
res=self.get_object()
ser=self.get_serializer(instance=res)
return Response(ser.data)
def put(self,request,pk):
res = self.get_object()
ser = self.get_serializer(instance=res, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功'}, status=201)
def delete(self,request,pk):
self.get_object().delete()
return Response('')