DRF - 视图组件
视图组件
0、APIView与Django原生的View类的区别
1.APIView中传入视图方法中的Request对象
是REST framework的Request对象
而不是Django的HttpRequest对象
2.视图方法可以返回REST framework的Response对象(使用的是drf的Response对象)
3.任何APIException异常都会被捕获到,并且处理成合适的响应信息
4.在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
1、两个视图基类
0.APIView类的属性
APIView类属性名称 | 作用 |
---|---|
renderer_classes | 响应格式 |
parser_classes | 能够解析的请求格式 |
authentication_classes | 认证类 |
throttle_classes | 频率类 |
permission_classes | 权限类 |
1.视图基类:APIView
APIView+ModelSerializer+Resposne写5个接口
(1)视图基于APIView + Response
class BookView(APIView): def get(self, request): books = Book.objects.all() ser = BookSerializer(instance=books, many=True) return Response(ser.data) def post(self, request): ser = BookSerializer(data=request.data) if ser.is_valid(): ser.save() # 咱们只有ser序列化类的对象,但是咱们想要的是新增的数据对象,然后序列化成字典。 # 但是,大前提是序列化类中新增的create方法一定要返回新增的对象, # 虽然我们没有写create方法,但是在ModelSerializer类中create方法,返回了新增了数据对象 return Response({'code': 100, 'msg': '新增成功', 'result': ser.data}) else: return Response({'code': 101, 'msg': ser.errors}) class BookDetailView(APIView): # 查询单条 def get(self, request, pk): books = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=books) return Response(ser.data) # 修改 def put(self, request, pk): books = Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=books, data=request.data) if ser.is_valid(): ser.save() return Response({'code': 100, 'msg': '修改成功', 'result': ser.data}) else: return Response({'code': 101, 'msg': ser.errors}) # 删除 def delete(self, request, pk): Book.objects.filter(pk=pk).delete() return Response({'code': 100, 'msg': '删除成功'})
(2)序列化类 基于ModelSerializer
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors'] extra_kwargs = {'name': {'max_length': 8}, 'publish_detail': {'read_only': True}, 'author_list': {'read_only': True}, 'publish': {'write_only': True}, 'authors': {'write_only': True}, }
(3)路由
urlpatterns = [ path('admin/', admin.site.urls), path('books/', views.BookView.as_view()), path('books/<int:pk>/', views.BookDetailView.as_view()), ]
2.视图基类GenericAPIView
GenericAPIView继承了APIView有很多新的属性和方法
(1)视图类中基于 GenericAPIView 来写接口
class BookView(GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request): # 如果通过get_queryset我们可以重写,扩展性更高 objs = self.get_queryset() # 可以通过重写get_serializer_class来控制哪个序列化类来做序列化 ser = self.get_serializer(instance=objs, many=True) return Response(ser.data) def post(self, request): ser = self.get_serializer(data=request.data) if ser.is_valid(): ser.save() # 咱们只有ser序列化类的对象,但是咱们想要的是新增的数据对象,然后序列化成字典。 # 但是,大前提是序列化类中新增的create方法一定要返回新增的对象, # 虽然我们没有写create方法,但是在ModelSerializer类中create方法,返回了新增了数据对象 return Response({'code': 100, 'msg': '新增成功', 'result': ser.data}) else: return Response({'code': 101, 'msg': ser.errors}) class BookDetailView(GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer # 查询单条 def get(self, request, pk): books = self.get_object() ser = BookSerializer(instance=books) return Response(ser.data) # 修改 def put(self, request, pk): books = self.get_object() ser = self.get_serializer(instance=books, data=request.data) if ser.is_valid(): ser.save() return Response({'code': 100, 'msg': '修改成功', 'result': ser.data}) else: return Response({'code': 101, 'msg': ser.errors}) # 删除 def delete(self, request, pk): self.get_object().delete() return Response({'code': 100, 'msg': '删除成功'})
3.基于GenericAPIView与5个视图拓展类
(1)GenericAPIView的属性和方法
- 属性
1)queryset:要序列化或者反序列化的表模型数据
2)serializer_class 使用的序列化类
3)lookup_field 查询单条的路由分组出来的字段名
4)filter_backends 过滤类的配置
5)pagination_class 分页器的配置
- 方法
1)get_queryset 获取要序列化的对象
2)get_object 获取单个对象
3)get_serializer 获取序列化类,跟它差不多的get_serializer_class 一般重写
4)filter_queryset 过滤有关系
genericAPIView()
(2)5个视图拓展类
GenericAPIView封装了5个视图拓展类,分别对应5个接口
- get请求 查询所有:ListModelMixin-->list方法
- get请求 查询一个:RetrieveModelMixin-->Retrieve方法
- post请求 新增一个:CreateModelMixin-->Create方法
- put请求 修改一个:UpdateModelMixin-->Update方法
- delete请求 删除一个:DestroyModelMixin-->Destroy方法
在5个视图类中,封装的不是get方法或者post方法,虽然名字不叫get方法或者post方法,但是和其内容一致
所以必须要配合 GenericAPIView 视图基类来使用,不然会报错
1.views.py中编写视图类
基于GenericAPIView封装的5个视图拓展类编写
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \ ListModelMixin class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request) class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer # 查询单条 def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) # 修改 def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) # 删除 def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
2.序列化类
class BookSerializer(serializers.ModelSerializer): # 跟表有关联 class Meta: model = Book fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors'] extra_kwargs = {'name': {'max_length': 8}, 'publish_detail': {'read_only': True}, 'author_list': {'read_only': True}, 'publish': {'write_only': True}, 'authors': {'write_only': True}, }
3.路由
urlpatterns = [ path('books/', views.BookView.as_view()), path('books/<int:pk>/', views.BookDetailView.as_view()), ]
2、9个视图子类
9个视图子类,不需要额外继承GenericAPIView,只要继承9个中其中某个,就会有某个或某几个接口
1.9个视图子类对应的请求与功能
视图子类 | 请求 | 功能 |
---|---|---|
CreateAPIView | post | 新增 |
ListAPIView | get | 查询所有 |
RetrieveAPIView | get | 查询一个 |
DestroyAPIView | delete | 删除 |
UpdateAPIView | put、patch | 修改 |
ListCreateAPIView | get、post | 查询所有、新增 |
RetrieveUpdateAPIView | get、put、patch | 查询一个、修改 |
RetrieveDestroyAPIView | get、delete | 查询一个、删除 |
RetrieveUpdateDestroyAPIView | get、put、patch、delete | 查询一个、修改、删除 |
2.基于9个视图子类编写接口
"第四层:基于9个视图子类编写接口" from rest_framework.generics import ListAPIView, ListCreateAPIView, CreateAPIView, RetrieveAPIView, \ RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView # 查询所有 新增一个 class BookView(ListCreateAPIView): # 查询所有新增一个 queryset = Book.objects.all() serializer_class = BookSerializer # get 和 post通过继承已经写好了 # 查询一个,修改一个,删除一个 class BookDetailView(RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer # get put delete
- ListCreateAPIView源码
- RetrieveUpdateDestroyAPIView源码
3.多种混和编写接口
可以通过九个的组合,来实现多种功能的实现
(1)ListAPIView
查询所有, CreateAPIView 新增一个
(2)ListAPIView
+ CreateAPIView
= ListCreateAPIView
(3)RetrieveAPIView
查询一个 , DestroyAPIView
删除 , UpdateAPIView
修改
(4)RetrieveDestroyAPIView
查找一个和删除 RetrieveUpdateAPIView
查找一个和修改,但是不存在Destroy和Update的组合
(5)RetrieveUpdateDestroyAPIView
查询一个、修改、删除
3、视图集
第五层。五个接口还是需要写两个视图类,配置两条路由
- 但是两个视图类写成一个,
- 路由不同
- 会有两个get方法
- drf中的类 ModelViewSet 只要继承他,5个接口都有,但是路由写法变了
1.通过ModelViewSet类编写5个接口
路由的写法改变了,但是视图类只用写一个
- 路由
# 路由 urlpatterns = [ path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})), path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), ]
- 视图类
class BookView(ModelViewSet): # 查询所有,新增一个 queryset = Book.objects.all() serializer_class = BookSerializer
2.通过ReadOnlyModelViewSet编写只读接口
- 路由
urlpatterns = [ path('books/', views.BookView.as_view({'get': 'list'})), path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve'})), ]
- 视图类
class BookView(ReadOnlyModelViewSet): # 查询所有,新增一个 queryset = Book.objects.all() serializer_class = BookSerializer
4.from rest_framework.viewsets
包下的类
1.ModelViewSet - 路由写法变了,只需要写两行,5个接口都有
- 5个视图扩展类
- ViewSetMixin
- GenericAPIView
2.ReadOnlyModelViewSet - 路由写法变了,只需要写两行,2个只读接口都有
-
2个视图扩展类
-
ViewSetMixin
-
GenericAPIView
3.ViewSetMixin 魔法类
重写了as_view,所以只要继承ViewSetMixin后,路由的写法都需要变成映射方法
4.ViewSet - 想用APIView
- ViewSetMixin + APIView
5.GenericViewSet - 想用GenericAPIView
- ViewSetMixin + GenericAPIView
- 想继承APIView,但是想改变路由写法并且视图类中方法名可以任意命名,需要继承ViewSet
- 想继承GenericAPIView,但是想改变路由写法并且视图类中方法名可以任意命名,要继承GenericViewSet
5.路由写法改变的原因
(1)GenericViewSet
GenericViewSet =
导致路由配置改变了形式
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
(2)ViewSetMixin源码分析
-->属性的查找顺序从左往右,由于ViewSetMixin中有as_view方法,则先执行ViewSetMixin中的as_view方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY