本系列文章中的上一篇文章:ListModelMixin, CreateModelMixin, RetrieveModelMixin, ListCreateAPIView
ViewSet
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView
from rest_framework import serializers
from rest_framework.response import Response
from models import Book
class BookViewSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# 查看所有书籍的 get 和 添加一本书籍的 post 方法
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookViewSerializers
# 查看某本书籍的 get 和 编辑某本书籍的 put
class BookDetailView(RetrieveUpdateAPIView):
queryset = Book.objects.all()
serializer_class = BookViewSerializers
""" BookView 中的 get 方法是查看所有书籍,post 方法是添加一本书籍 而 BookDetailView 中的 get 和 put 分别是查看和编辑某本书籍信息 因为两个类都有 get 方法,所以不能写在一个类中,否则会冲突 urls.py 文件中的代码 path("book/", BookView.as_view()) re_path("book/(?P<pk>\d+)", BookDetailView.as_view()) 这两个类对应的路由不一样,BookDetailView 需要在路由中传递书籍的 id 值 现在 BookView 和 BookDetailView 两个类中还是有相同的部分 可以把它们合并在一起写,只需要继承 ViewSet 类 """
from rest_framework.viewsets import ViewSet
class BookView(ViewSet):
"""
我们可以为增删改查自定义方法名字,但是这样做原生的 APIView 的分发机制就找不到对应的请求方法
从而就不能根据 URL 匹配执行正确的视图函数
而 ViewSet 的作用就是重写原生 APIView 的分发机制,见以下 ViewSet 源码
"""
def get_all(self, request):
return Response("查看所有资源")
def add_object(self, request):
return Response("添加资源")
def get_object(self, request, pk):
return Response("查看单一资源")
def update_object(self, request, pk):
return Response("更新单一资源")
def delete_object(self, request, pk):
return Response("删除单一资源")
urls.py 中的代码如下:
"""
urls.py 中的代码
path("book/", BookView.as_view({"get": "get_all", "post": "add_object"}))
re_path("book/(?P<pk>\d+)",
BookView.as_view({
"get": "get_object",
"put": "update_object",
"delete": "delete_object"
}))
"""
ViewSet 源码如下:
""" ViewSet 源码 class ViewSet(ViewSetMixin, views.APIView): pass class ViewSetMixin: # ViewSetMixin 集重写了 as_view() 方法 # 当有请求过来时,匹配到某个 URL 时调用的 as_view() 方法会调用本类中的 as_view # 而不是调用 APIView 中 as_view ,因为 ViewSet 是先继承 ViewSetMixin 再继承 APIView @classonlymethod def as_view(cls, actions=None, **initkwargs): # ... def view(request, *args, **kwargs): # ... # 与 APIView 中的 as_view 方法不同的地方就在此处 # actions 接收的就是 as_view 方法中传递过来的字典 # 如 actions = {"get": "get_all", "post": "add_object"} for method, action in actions.items(): # handler 得到的就是我们在 BookView 类中自定义的那些方法 # 如 handler = self.get_all => handler = get_all handler = getattr(self, action) # 再将获取到的自定义方法和对应的请求方法进行绑定 # 如 self.get = get_all # 当有一个 get 请求时,就会执行对应的自定义方法 setattr(self, method, handler) # ... # 调用的还是 APIView 中的 dispatch() ,因为 ViewSetMixin 类没有实现该方法 return self.dispatch(request, *args, **kwargs) # ... return csrf_exempt(view) """
GenericViewSet
使用 ViewSet 中继承的是原生的 APIView ,不能使用 get_object、get_serializer 等方法 所以使用 GenericViewSet ,它继承的是 GenericAPIView
urls.py 中的代码
urls.py 中的代码 path("book/", BookView.as_view({"get": "list", "post": "create"})) re_path("book/(?P<pk>\d+)", BookView.as_view({ "get": "retrieve", "put": "destroy", "delete": "update" }))
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin
class BookView(GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin):
queryset = BookView.objects.all()
serializer_class = BookViewSerializers
GenericViewSet 源码:
""" GenericViewSet 源码 class GenericViewSet(ViewSetMixin, generics.GenericAPIView): pass 假设匹配路由 path("book/", BookView.as_view({"get": "list", "post": "create"})) 当执行到 ViewSetMixin 中的 as_view 方法时,里面的 view 方法: @classonlymethod def as_view(cls, actions=None, **initkwargs): # ... def view(request, *args, **kwargs): # ... # actions = {"get": "list", "post": "create"} for method, action in actions.items(): # handler = self.list # BookView 中没有 list 方法,但是它的父类 ListModelMixin 中有 # 所以 handler = ListModelMixin.list # 同理,下一次循环 handler = ListModelMixin.create handler = getattr(self, action) setattr(self, method, handler) """
ModelViewSet
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = BookView.objects.all()
serializer_class = BookViewSerializers
ModelViewSet 源码如下:
""" ModelViewSet 类就是继承了 GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin 这几个类 源码如下: class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): pass """