当前位置:网站首页>drf视图组件
drf视图组件
2022-08-02 14:01:00 【意大利面拌42号混凝土】
Python之drf视图组件
一、局部校验全局校验源码分析
截取一段views.py里的代码
def post(self, request):
back_dic = {
'code': 200, 'msg': '新增成功', 'result': ''}
result = BookModelSerializer(data=request.data)
if not result.is_valid():
return Response(result.errors)
result.save() # 保存数据
back_dic['result'] = result.data
return Response(back_dic)
里面的序列化类对象点is_valid(),是校验反序列化数据过来的的合法性
…………
二、序列化组件源码分析
序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
当参数传过去,判断是方法就加括号执行,是属性就把值取出来
三、请求与响应
1、Request
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果
无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。
1).data
request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,但提供如下特性:
- 包含了解析之后的文件和非文件数据
- 包含了对POST、PUT、PATCH请求方式解析后的数据
- 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
2).query_params
request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。
3)drf配置请求格式
# 通过配置,设置后端接口支持的编码格式,默认支持三种
# 1、可以在项目的settings.py配置文件中配置,在这种称之为“全局配置”
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser', # json
'rest_framework.parsers.FormParser', # urlencoded
'rest_framework.parsers.MultiPartParser' # form-data文件格式
]
}
# 2、局部配置,在视图类中写类属性
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
parser_classes = [JSONParser,] # 局部配置默认此方法只接受json格式数据
2、Response
from rest_framework.response import Response
Response(data, status=None, template_name=None, headers=None, content_type=None)
1)返回数据
data数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data。
data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了Python字典类型)再传递给data参数。
参数说明:
data: 为响应准备的序列化处理后的数据;status: 状态码,默认200;template_name: 模板名称,如果使用HTMLRenderer时需指明;headers: 用于存放响应头信息的字典;content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
状态码可以写数字,也可以导入的status包,写状态码的常量
from rest_framework import status
# 如下使用
return Response(back_dic,status=status.HTTP_200_OK)
return Response(back_dic,status=status.HTTP_404_NOT_FOUND)
2)drf配置响应格式
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渲染器
]
}
3)自己封装Response对象
1、以后都使用自己自定义封装的response
class APIResponse(Response):
def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs):
dic = {
'code': code, 'msg': msg}
if data:
dic['data'] = data
dic.update(kwargs) # 这里使用update
super(APIResponse,self).__init__(data=dic, status=status,
template_name=None, headers=headers,
exception=False, content_type=content_type)
2、使用
return APIResponse(code=100,msg='查询成功',data=ser.data,count=200,next='http://xxx.com')
四、两个视图基类
1、APIView
from rest_framework.views import APIView
APIView是REST framework提供的所有视图的基类,继承自Django的View父类。
APIView与View的不同之处在于:
- 传入到视图方法中的是REST framework的
Request对象,而不是Django的HttpRequeset对象; - 视图方法可以返回REST framework的
Response对象,视图会为响应数据设置(render)符合前端要求的格式; - 任何
APIException异常都会被捕获到,并且处理成合适的响应信息; - 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
在APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
class publish(APIView):
# 获取所有出版社接口
def get(self,request):
back_dic = {
'code':200,'msg':'查询成功','result':''}
res = models.Publish.objects.all()
result = PublishModelSerializer(instance=res,many=True)
back_dic['result'] = result.data
return Response(back_dic)
2、GenericAPIView[通用视图类]
from rest_framework.generics import GenericAPIView
继承自APIVIew,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
''' 有两个类属性 queryset = Book.objects.all() # 你要序列化的数据 serializer_class = serializer.BookSerializer # 你要使用的序列化类 三个方法 get_queryset() # 获取要序列化的数据 get_serializer() # 获取要使用的序列化类 get_object() # 获取单条数据(一定要用pk,如果你想改,重写类属性lookup_field) '''
# 使用GenericAPIView 通用视图类
from rest_framework.generics import GenericAPIView
# 书籍 无参
class Book(GenericAPIView):
queryset = models.Book.objects.all() # 获取所有数据的queryset对象
serializer_class = BookModelSerializer # 获取到将要使用到的序列化的类
# 获取所有图书接口
def get(self, request):
back_dic = {
'code': 200, 'msg': '查询成功', 'result': ''}
res = self.get_queryset() # 获取所有数据
result = self.get_serializer(instance=res, many=True) # 使用BookModelSerializer序列化类
back_dic['result'] = result.data
return Response(back_dic)
def post(self, request):
back_dic = {
'code': 200, 'msg': '新增成功', 'result': ''}
result = self.get_serializer(data=request.data)
if not result.is_valid():
return Response(result.errors)
result.save() # 保存数据
back_dic['result'] = result.data
return Response(back_dic)
class Book_param(GenericAPIView):
queryset = models.Book.objects.all() # 获取所有数据的queryset对象
serializer_class = BookModelSerializer # 获取到将要使用到的序列化的类
def get(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '查询成功', 'result': ''}
res = self.get_object() # 获取单条数据
result = self.get_serializer(instance=res)
back_dic['result'] = result.data
return Response(back_dic)
def delete(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '删除成功'}
models.Book.objects.filter(**kwargs).delete()
return Response(back_dic)
def put(self,request,**kwargs):
back_dic = {
'code': 200, 'msg': '修改成功', 'result': ''}
res = self.get_object()
result = self.get_serializer(instance=res,data=request.data)
if result.is_valid() ==False:
return Response(result.errors)
result.save()
back_dic['result'] = result.data
return Response(back_dic)
五、五个视图扩展类
提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
1、ListModelMixin
列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
该方法就是获取到所有对象
源码:
class ListModelMixin:
""" List a queryset. """
def list(self, request, *args, **kwargs):
# 过滤
queryset = self.filter_queryset(self.get_queryset())
# 分页
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
# 序列化
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
2、CreateModelMixin
创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin:
""" Create a model instance. """
def create(self, request, *args, **kwargs):
# 获取序列化qi
serializer = self.get_serializer(data=request.data)
# 数据校验
serializer.is_valid(raise_exception=True)
# 调用perform_create方法保存,以后再有其他需求可以重写perform_create方法
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {
'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {
}
3、RetrieveModelMixin
详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
class RetrieveModelMixin:
""" Retrieve a model instance. """
def retrieve(self, request, *args, **kwargs):
# 获取单个对象,会检查对象的权限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance)
return Response(serializer.data)
4、UpdateModelMixin
更新试图扩展类,提供update(self, request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象
同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin:
""" Update a model instance. """
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
# 获取单个对象,会检查对象的权限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance, data=request.data, partial=partial)
# 校验数据
serializer.is_valid(raise_exception=True)
# 调用perform_update方法保存数据,后期根据业务需求可以重写perform_update方法
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {
}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
5、DestroyModelMixin
删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class DestroyModelMixin:
""" Destroy a model instance. """
def destroy(self, request, *args, **kwargs):
# 获取单个对象,会检查对象的权限
instance = self.get_object()
# 调用perform_destroy方法删除数据,后期根据业务需求可以重写perform_update方法
self.perform_destroy(instance)
# 返回状态码
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
6、综合
# 使用GenericAPIView 通用视图类
from rest_framework.generics import GenericAPIView
# 使用五个试图扩展类
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
# 书籍 无参
class Book(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = models.Book.objects.all() # 获取所有数据的queryset对象
serializer_class = BookModelSerializer # 获取到将要使用到的序列化的类
# 获取所有图书接口
def get(self, request):
# back_dic = {'code': 200, 'msg': '查询成功', 'result': ''}
# res = self.get_queryset() # 获取所有数据
# result = self.get_serializer(instance=res, many=True) # 使用BookModelSerializer序列化类
#
# back_dic['result'] = result.data
return self.list(request)
def post(self, request):
return self.create(request)
class Book_param(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = models.Book.objects.all() # 获取所有数据的queryset对象
serializer_class = BookModelSerializer # 获取到将要使用到的序列化的类
def get(self,request,**kwargs):
return self.retrieve(self,request,**kwargs)
def delete(self,request,**kwargs):
return self.update(self,request,**kwargs)
def put(self,request,**kwargs):
return self.destroy(self,request,**kwargs)
六、GenericAPIView九个视图子类
1、ListAPIView
提供get方法(获取所有)
继承自:GenericAPIView,ListModelMixin
2、CreateAPIView
提供post方法
继承自:GenericAPIView,CreateModelMixin
3、RetrieveAPIView
提供get方法(获取单个)
继承自:GenericAPIView,RetrieveModelMixin
4、UpdateAPIView
提供update方法
继承自:GenericAPIView,UpdateModelMixin
5、DestroyAPIView
提供delete方法
继承自:GenericAPIView,DestroyModelMixin
6、ListCreateAPIView
提供get,put,patch方法
继承自:GenericAPIView,ListModelMixin,RetrieveModelMixin
7、RetrieveDestroyAPIView
提供get,delete方法
继承自:GenericAPIView,DestroyModelMixin
8、RetrieveUpdateAPIView
提供get,put,patch方法
继承自:GenericAPIView,RetrieveModelMixin,UpdateModelMixin
9、 RetrieveUpdateDestoryAPIView
提供get,put,patch,delete方法
继承自:GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
10、总结
# 使用GenericAPIView 通用视图类
# from rest_framework.generics import GenericAPIView
# 使用九个视图扩展类
from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView
# 书籍 无参
class Book(ListCreateAPIView):
queryset = models.Book.objects.all() # 获取所有数据的queryset对象
serializer_class = BookModelSerializer # 获取到将要使用到的序列化的类
class Book_param(RetrieveUpdateDestroyAPIView):
queryset = models.Book.objects.all() # 获取所有数据的queryset对象
serializer_class = BookModelSerializer # 获取到将要使用到的序列化的类
七、视图集ViewSet
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中
- list() 提供一组数据
- retrieve() 提供单个数据
- create() 创建数据
- update() 保存数据
- destory() 删除数据
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
class BookInfoViewSet(viewsets.ViewSet):
def list(self, request):
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
books = BookInfo.objects.get(id=pk)
except BookInfo.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = BookInfoSerializer(books)
return Response(serializer.data)
在设置路由时,我们可以如下操作
urlpatterns = [
path('books/', BookInfoViewSet.as_view({
'get':'list'}),
path('books/<int:pk>', BookInfoViewSet.as_view({
'get': 'retrieve'})
]
1、常用视图集父类
1、ViewSet
继承自APIView与ViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
2、GenericAPIView
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
url的定义
urlpatterns = [
path("students7/", views.Student4ViewSet.as_view({
"get": "list", "post": "create"})),
re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({
"get": "retrieve","put":"update","delete":"destroy"})),
]
3、ModelViewSet
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。(五个视图扩展类)
4、ReadOnlyModelViewSet
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。
2、视图集中定义附加action动作
在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def login(self,request):
"""学生登录功能"""
return Response({
"message":"登录成功"})
url的定义
urlpatterns = [
path("students8/", views.StudentModelViewSet.as_view({
"get": "list", "post": "create"})),
re_path("students8/(?P<pk>\d+)/",
views.StudentModelViewSet.as_view({
"get": "retrieve", "put": "update", "delete": "destroy"})),
path("stu/login/",views.StudentModelViewSet.as_view({
"get":"login"})) # 自定义action动作
]
八、总结
#两个基类
APIView
GenericAPIView:有关数据库操作
类属性:queryset 和serializer_class
方法:self.get_queryset(),self.get_serializer()和self.get_object()
#5个视图扩展类(rest_framework.mixins)
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条
#9个子类视图(rest_framework.generics)
CreateAPIView:继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条
ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除
#视图集
ViewSetMixin:重写了as_view
ViewSet: 继承ViewSetMixin和APIView
GenericViewSet:继承ViewSetMixin, generics.GenericAPIView
ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet
边栏推荐
- 关于Google词向量模型(googlenews-vectors-negative300.bin)的导入问题
- ttl电平与rs232电平转换电路(232电平定义)
- WeChat Mini Program-Recent Dynamic Scrolling Implementation
- 存储过程详解
- 网络安全第二次作业
- How to solve mysql service cannot start 1069
- C语言提高篇(三)
- 如何解决mysql服务无法启动1069
- Why does a four-byte float represent a wider range than an eight-byte long
- What is the difference between web testing and app testing?
猜你喜欢

定了!就在7月30日!

Cloin 控制台乱码

Break the limit of file locks and use storage power to help enterprises grow new momentum

面试SQL语句,学会这些就够了!!!

动态刷新日志级别

A number of embassies and consulates abroad have issued reminders about travel to China, personal and property safety

世界上最大的开源基金会 Apache 是如何运作的?

监管再次重拳出击,后市如何?2021-05-22

玉溪卷烟厂通过正确选择时序数据库 轻松应对超万亿行数据

shell脚本“画画”
随机推荐
VMM是什么?_兮是什么意思
What are the file encryption software?Keep your files safe
世界上最大的开源基金会 Apache 是如何运作的?
如何选择正规的期货交易平台开户?
FreeBSD bnxt以太网驱动源码阅读记录三:
期货具体是如何开户的?
C语言提高篇(三)
网络安全第四次作业
mysql的case when如何用
C# 编译错误:Compiler Error CS1044
Raft对比ZAB协议
logback源码阅读(二)日志打印,自定义appender,encoder,pattern,converter
Sentinel源码(四)(滑动窗口流量统计)
瑞吉外卖笔记——第10讲Swagger
数据机构---第六章图---图的遍历---选择题
一维卷积神经网络_卷积神经网络的基础知识「建议收藏」
Mysql's case the when you how to use
【Tensorflow】AttributeError: '_TfDeviceCaptureOp' object has no attribute '_set_device_from_string'
Large and comprehensive pom file example
Raft协议图解,缺陷以及优化