第三版
from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from djangoDemo.models import Book # 导入表 from .serializers import BookSerializer class GenericAPIView(APIView): # 通用的API视图 queryset = None serializer_class = None def get_queryset(self): # 这里要加.all() 虽然下面的ORM查询出来的是所有的数据 # 但是由于DRF的内部机制,这里如果不加就会报错 return self.queryset.all() def get_serializer(self, *args, **kwargs): # 不同请求的序列化器里传的参数是不一样的 return self.serializer_class(*args, **kwargs) class ListModelMixin(object): # get方法,查询所有数据 def list(self, request): queryset = self.get_queryset() ser_obj = self.get_serializer(queryset, many=True) return Response(ser_obj.data) class CreateModelMixin(object): # post方法 def create(self, request): ser_obj = self.get_serializer(data=request.data) if ser_obj.is_valid(): ser_obj.save() return Response(ser_obj.validated_data) return Response(ser_obj.errors) class RetrieveModelMixin(object): # get方法,查询单条数据 def retrieve(self, request, id): # 先查询出所有,在过滤,在取第一个 book_obj = self.get_queryset().filter(id=id).first() ser_obj = self.get_serializer(book_obj) return Response(ser_obj.data) class UpdateModelMixin(object): # put方法 def update(self, request, id): book_obj = self.get_queryset().filter(id=id).first() ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True) if ser_obj.is_valid(): ser_obj.save() return Response(ser_obj.data) # 返回数据,注意不是ser_obj.validated_data return Response(ser_obj.errors) class DestroyModelMixin(object): # delete方法 def destoy(self, request, id): book_obj = self.get_queryset().filter(id=id).first() if not book_obj: return Response('删除的对象不存在') book_obj.delete() return Response('Success') class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass class BookView(ListCreateAPIView): # 查询所有数据和添加数据的方法 queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request): return self.list(request) # 调用get方法 def post(self, request): return self.create(request) # 调用post方法 class BookEditView(RetrieveUpdateDestroyAPIView): # 查询单条数据和put、delete方法 queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, id): return self.retrieve(request, id) def put(self, request, id): return self.update(request, id) def delete(self, request, id): return self.destoy(request, id)
第四版
上面有两个get方法,一个是查询一条,一个是查询多条。那我们可不可以通过路由传参的方式来解决呢?只让它走一个,路由类似于这样
urlpatterns = [ # url(r'^book/$', BookView.as_view()), # url(r'^book/(?P<id>\d+)', BookEditView.as_view()), url(r'^book/$', BookView.as_view({"get": "list", "post": "create"})), url(r'^book/(?P<id>\d+)', BookEditView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), ]
我们知道在CBV中,在执行视图函数时会先执行dispatch方法,我们继承了APIView,来看看源码是怎样写的,APIView里的as_view方法代码如下
View Code
这里可以看到可以传参,在去看看父类的as_view方法(第十七行)
View Code
很显然,从源代码里可以看出,父类的as_view也可以接收字典类型的传参,但是,如果key在initkwargs里,就会抛出一个错误(第七行),所以我们传参肯定会报错的,既然这样,那我们可以重写as_view方法,DRF已经替我们想好了,也替我们封装了,我们只需要使用就可以了,导入
from rest_framework.viewsets import ViewSetMixin
可以点进入看91到93行的源码
for method, action in actions.items(): handler = getattr(self, action) setattr(self, method, handler)
这里,action 就是我们传来的参数,for循环之后,method就是原来的get请求,action就是我们写的list方法({"get":"list"})。然后通过setattr,执行get时,就会去执行我们写的list方法。
我们可以写个ModelViewSet类,来继承我们的两个get方法
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): pass
然后再写个类,让它继承这个类
class BookModelView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
在来改写路由
from django.conf.urls import url, include from .views import BookModelView urlpatterns = [ url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})), url(r'^book/(?P<id>\d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), ]
这样我们所有的请求就都会去执行BookModelView视图了。
终极版
上面我们封装了那么多的类,其实DRF已经给我们封装好了,我们写的所有类都在下面的几个类里面,只是比我们自己写的全很多
from rest_framework import views from rest_framework import viewsets from rest_framework import generics from rest_framework import mixins
我们进入viewsets里面看看最后的代码
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass
这里已经写好了,所以我们只需要继承ModelViewSet就可以了
只需要导入 from rest_framework import viewsets,继承就可以了,通过继承就可以看出,前面我们写了上百行的代码,只需要六行就实现了,这就上python的强大之处
from djangoDemo.models import Book # 导入表 from .serializers import BookSerializer from rest_framework import viewsets class BookModelView(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
然后再改写路由
from django.conf.urls import url, include from .views import BookModelView urlpatterns = [ url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})), url(r'^book/(?P<pk>\d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), ]
注意:路由分组命名那里要为pk,否则会报错
这样,简单的代码就实现了我们上面所有的代码