drf-视图组件
一、视图
Django REST framwork 提供的视图的主要作用:
- 控制序列化器的执行(检验、保存、转换数据)
- 控制数据库查询的执行
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
1. 两个视图基类
1.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() 或者其他请求方式的方法。
###### 第一层: 继承APIView编写book5个接口 from rest_framework.views import APIView from rest_framework.response import Response from .serializer import BookSerializer from .models import Book class BookView(APIView): def get(self, request): book_list = Book.objects.all() ser = BookSerializer(instance=book_list, many=True) return Response(ser.data) def post(self, request): ser = BookSerializer(data=request.data) if ser.is_valid(): ser.save() # 反序列化保存 return Response(ser.data) # 创建成功后,返回创建后的对象, 做了个序列化 else: return Response(ser.errors)
class BookDetailView(APIView): def get(self, request, pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book) return Response(ser.data) def put(self, request, pk): book = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book, data=request.data) if ser.is_valid(): ser.save() return Response(ser.data) else: return Response(ser.errors) def delete(self, request, pk): Book.objects.filter(pk=pk).delete() return Response('')
1.2 GenericAPIView[通用视图类]
from rest_framework.generics import GenericAPIView
继承了APIVIew
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
提供的关于数据库查询的属性与方法
写get_queryset的目的:后期通过重写
-
### 重要属性:
- queryset : 以后放所有某个表查询出的数据
- Serializer_class : 要序列化的类
- get_object :修改,查询的单条
-
### 重要方法###
-get_queryset :要序列化的所有数据,qs对象
-get_serializer :序列化类
-get_object :修改,查询,删除 的单条 -
了解类属性:
-
lookup_field = 'pk' 路由使用转换器,转换出来的参数,查询单条要用到,如果改了,路由对应也要修改,一般不改
- filter_backends:后面详细讲 过滤 功能
- pagination_class :后面详细讲 分页
-
-
了解方法:
-
get_serializer_class 后期咱们可能会重写它,指定某些方法使用不同的序列化类
- filter_queryset 后面跟过滤功能一起讲
-
代码:
from rest_framework.generics import GenericAPIView from .models import Publish from .serializer import PublishSerializer class PublishView(GenericAPIView): # 本次视图类中要操作的数据 queryset = Publish.objects.all() # 类只要加载,就会执行,查了所有数据,不能以它为准 # 本次视图类中要调用的默认序列化器 serializer_class = PublishSerializer def get(self, request): # 获取所有的出版社数据 obj_list = self.get_queryset() # 以用的时候为准 # 使用对应的序列化类进行处理数据 ser = self.get_serializer(instance=obj_list, 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(ser.data) # 创建成功后,返回创建后的对象, 做了个序列化 else: return Response(ser.errors) class PublishDetailView(GenericAPIView): serializer_class = PublishSerializer # 要给这两个参数传对应的值 queryset = Publish.objects.all() def get(self, request, pk): # 查询对应PK的那条数据 obj = self.get_object() ser = self.get_serializer(instance=obj) return Response(ser.data) def put(self, request, pk): obj = self.get_object() ser = self.get_serializer(instance=obj, data=request.data) if ser.is_valid(): ser.save() return Response(ser.data) else: return Response(ser.errors) def delete(self, request, pk): self.get_object().delete() return Response('')
对应的序列化类:
class PublishSerializer(serializers.ModelSerializer): class Meta: model=Publish fields='__all__'
总结:
# 易犯的错误1:一定要在用数据的时候再查
def get_queryset(self):
return self.queryset.all()
# 错误2:咱么没有在类属性上配置 queryset这个参数--->源码中做了断言
2. 5个视图扩展类
作用:
提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
RetrieveModelMixin, 查询一条,写了一个方法 retrieve---》代码就是 跟咱们之前写获取单条get方法内容一样
CreateModelMixin 新增一条写了一个方法 create---》代码就是 跟咱们之前写新增一条 post 方法内容一样
DestroyModelMixin,删除一条写了一个方法 destroy---》代码就是 跟咱们之前写删除一条 delete 方法内容一样
ListModelMixin,查询所有写了一个方法 list---》代码就是 跟咱们之前写删除一条 get 方法内容一样
UpdateModelMixin 修改一个写了一个方法 update---》代码就是 跟咱们之前写删除一条put 方法内容一样
为什么要写5个视图扩展类,不写俩?
因为后期不一定 5个接口都写
代码:
class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Publish.objects.all() # 类只要加载,就会执行,查了所有数据,不能以它为准 serializer_class = PublishSerializer def get(self, request): return self.list(request) def post(self, request): # return self.create(request) # 一定不要忘了return return super().create(request) # 一定不要忘了return class PublishDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): serializer_class = PublishSerializer queryset = Publish.objects.all() def get(self, request, pk): return self.retrieve(request, pk) def put(self, request, pk): return self.update(request, pk) def delete(self, request, pk): return self.destroy(request, pk)
3. 9个视图子类
from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView
1. ListAPIView:提供get方法
继承自:GenericAPIView、ListModelMixin
2. CreateAPIView:提供了post方法
继承自:GenericAPIView、CreateModelMixin
3. ListCreateAPIView:提供了get、post方法
继承自:GenericAPIView、ListModelMixin、CreateModelMixin
from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView
4. RetrieveAPIView:提供了get方法
继承自:GenericAPIView、RetrieveModelMixin
5. DestroyAPIView:提供了delete方法
继承自:GenericAPIView、DestroyModelMixin
6. UpdateAPIView:提供了put方法
继承自:GenericAPIView、UpdateModelMixin
from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
7.RetrieveUpdateDestroyAPIView:提供了get、put、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin
8. RetrieveDestroyAPIView:提供了get、delete方法
继承自:GenericAPIView、RetrieveModelMixin、DestroyModelMixin
9.RetrieveUpdateAPIView:提供了get、put 方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin
以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性:queryset = XX.objectes.all()、serializer_class = XXSerializer
代码:
1. 利用九个视图子类来写接口
#1利用九个视图子类来写 #publish: 查询所有,查询单条,修改一条,新增一条,删除一条的接口 class PublishView(ListCreateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializerclass PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer #2 想写 publish: 查询单条,新增一条,的接口--->使用9个视图子类编写class PublishView(CreateAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializerclass PublishDetailView(RetrieveAPIView): queryset = Publish.objects.all() serializer_class = PublishSerializer
2. 利用五个视图扩展类来写接口
#3 想写 publish: 查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView class PublishView(GenericAPIView,CreateModelMixin): queryset = Publish.objects.all() serializer_class = PublishSerializer def post(self,request,*args,**kwargs): return self.create(request,*args,**kwargs) class PublishDetailView(GenericAPIView,RetrieveModelMixin): queryset = Publish.objects.all() serializer_class = PublishSerializer def get(self,request,*args,**kwargs): return self.retrieve(request,*args,**kwargs)
3. 路由:
path('publish/', PublishView.as_view()), path('publish/<int:pk>', PublishView.as_view()),
4. 视图集
1.
from rest_framework.viewsets import ModelViewSet class PublishView(ModelViewSet): queryset = Publish.objects.all() serializer_class = PublishSerializer
路由:
配置好请求方式和方法的对应关系
path('publish/', PublishView.as_view({'get':'list','post':'create'})), path('publish/<int:pk>', PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
1.1
然后发现在ViewSetMixin类中,重写了as_view方法,在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。
2. ViewSetMixin
ViewSetMixin决定了路由的写法,所以路由写法就变成了有对应关系,方法名可以随便写只要做好对应关系,如下:
path('publish/', PublishView.as_view({'get':'list','post':'create'})) path('publish/', PublishView.as_view({'get':'lqz'})) # 做好对应关系
原来执行的是APIView中的as_view,现在继承了ViewSetMixin后,执行的就是ViewSetMixin的as_view
GenericViewSe源码分析:
-class GenericViewSet(ViewSetMixin, generics.GenericAPIView):ViewSetMixin必须放前面--》保证执行的as_view是ViewSetMixin的
ViewSetMixin的源码分析:
对actions参数进行一个判断,当路由中没有传actions时,就会抛出异常,而且必须以字典的形式传actions。
-请求来了,路由匹配成功---》执行ViewSetMixin的as_view内的view(request)
ViewSetMixin的as_view内的view(request)源码分析:
# 总结:
-路由中这样配置:PublishView.as_view({'get':'list','post':'create'})
-以后get请求过来,本质执行的就是视图类中的list方法
只要继承的类是:ViewSetMixin ,就能视图类中方法任意命名,路由写法变化,以后视图类中方法名可以随意命名,只要路由做好映射
ReadOnlyModelViewSet:以后写的接口,只想有 获取单条和获取所有,继承它,只序列化
3. 视图类的总结
# 1 两个视图基类
-APIView和GenericAPIView
-APIView的执行流程:包装了新的 处理了csrfrequeset,执行了3大认证,处理全局异常
-GenericAPIView:要做序列化,要跟数据库打交道,就直接继承它即可
重要属性:
-queryset:以后放所有某个表查询出的数据
-serializer_class:要序列化的类
重要方法:
-get_object:查询、修改、删除的单条数据
-get_queryset:要序列化的所有的数据,qs对象
-get_serializer:序列化类
#2. 5个视图扩展类(不是视图类),需要GenericAPIView才能用
-快速使用5个接口
-某几个接口:查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView
class PublishView(GenericAPIView,CreateModelMixin)
queryset=Publish.objects.all()
serializer_class=序列化类
def post(self,request)
return self.create(request)
class PublishDetailView(GenericAPIView,RetrieveModelMixin)
queryset=Publish.objects.all()
serializer_class=序列化类
def get(self,request)
return self.retrieve(request)
#3. 9个视图子类(继承GenericAPIView+5个视图扩展类的组合)
ListAPIView, CreateAPIView
ListCreateAPIView
RetrieveAPIView, DestroyAPIView, UpdateAPIView
RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
# 4 视图集 -ModelViewSet:
-ViewSetMixin+GenericAPIView+5个视图扩展类
-GenericViewSet+5个视图扩展类
-ViewSetMixin源码:路由做映射的配置,以后视图类中方法可以随便命名
-Viewset:ViewSetMixin+APIView---》不需要要序列化,路由写法变了
-GenericViewSet:ViewSetMixin+GenericAPIView--》需要序列化,需要用数据库,路由写法变化
-ReadOnlyModelViewSet:list和retrieve
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人