
DRF 视图和路由
Django Rest Feamework 视图和路由DRF的视图APIView我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不同呢urlpatterns = [url(r'^book$', BookView.as_view()),url(r'^book/(?P<id>d+)$', BookEditView.as_view()),]我们可以看到,不管是View还是APIView最开始调用的都是as_view()方法~~那我们走进源码看看~~我们能看到,APIView继承了View, 并且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。那我们看看View中的as_view()方法做了什么~我们看到了~在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法~~但是这里的dispatch方法应该是我们APIView中的~~我们去initialize_request中看下把什么赋值给了request,并且赋值给了self.request, 也就是我们在视图中用的request.xxx到底是什么~~我们看到,这个方法返回的是Request这个类的实例对象~~我们注意我们看下这个Request类中的第一个参数request,是我们走我们django的时候的原来的request~我们看到了,这个Request类把原来的request赋值给了self._request, 也就是说以后_request是我们老的request,新的request是我们这个Request类~~那我们继承APIView之后请求来的数据都在哪呢~~我们用了rest_framework框架以后,我们的request是重新封装的Request类~request.query_params 存放的是我们get请求的参数request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求~~~相比原来的django的request,我们现在的request更加精简,清晰了~~~现在我们知道了APIView和View的一些区别~~当然还有~~后面我们还会说~~我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码~~那么我们尝试着来进行封装一下~~第一次封装class BookView(APIView):def get(self, request):query_set = Book.objects.all()book_ser = BookSerializer(query_set, many=True)return Response(book_ser.data)def post(self, request):query_set = request.databook_ser = BookSerializer(data=query_set)if book_ser.is_valid():book_ser.save()return Response(book_ser.validated_data)else:return Response(book_ser.errors)class BookEditView(APIView):def get(self, request, id):query_set = Book.objects.filter(id=id).first()book_ser = BookSerializer(query_set)return Response(book_ser.data)def patch(self, request, id):query_set = Book.objects.filter(id=id).first()book_ser = BookSerializer(query_set, data=request.data, partial=True)if book_ser.is_valid():book_ser.save()return Response(book_ser.validated_data)else:return Response(book_ser.errors)def delete(self, request, id):query_set = Book.objects.filter(id=id).first()if query_set:query_set.delete()return Response("")else:return Response("删除的书籍不存在")APIView视图class GenericAPIView(APIView):queryset = Noneserializer_class = Nonedef get_queryset(self):return self.queryset.all()def get_serializer(self, *args, **kwargs):return self.serializer_class(*args, **kwargs)class ListModelMixin(object):def list(self, request, *args, **kwargs):queryset = self.get_queryset()serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)class CreateModelMixin(object):def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.validated_data)else:return Response(serializer.errors)class RetrieveModelMixin(object):def retrieve(self, request, id, *args, **kwargs):book_obj = self.get_queryset().filter(pk=id).first()book_ser = self.get_serializer(book_obj)return Response(book_ser.data)class UpdateModelMixin(object):def update(self, request, id, *args, **kwargs):book_obj = self.get_queryset().filter(pk=id).first()book_ser = self.get_serializer(book_obj, data=request.data, partial=True)if book_ser.is_valid():book_ser.save()return Response(book_ser.validated_data)else:return Response(book_ser.errors)class DestroyModelMixin(object):def destroy(self, request, id, *args, **kwargs):queryset = self.get_queryset()try:queryset.get(pk=id).delete()return Response("")except Exception as e:return Response("信息有误")# 我们把公共的部分抽出来 这样不管写多少表的增删改查都变的很简单# 这样封装后我们的视图会变成这样class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):queryset = Book.objects.all()serializer_class = BookSerializerdef get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)def post(self, request, *args, **kwargs):return self.create(request, *args, **kwargs)class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):queryset = Book.objects.all()serializer_class = BookSerializerdef get(self, request, id, *args, **kwargs):return self.retrieve(request, id, *args, **kwargs)def patch(self, request, id, *args, **kwargs):return self.update(request, id, *args, **kwargs)def destroy(self, request, id, *args, **kwargs):return self.delete(request, id, *args, **kwargs)第一次封装我们封装的GenericAPIView,包括封装每个方法的类,其实框架都帮我们封装好了我们可以直接继承这些类~~来实现上面的视图~~可是还有没有更简单的方法呢~我们再次封装一下第二次封装# 上面我们写的继承类太长了~~我们再改改class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):passclass RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):passclass BookView(ListCreateAPIView):queryset = Book.objects.all()serializer_class = BookSerializerdef get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)def post(self, request, *args, **kwargs):return self.create(request, *args, **kwargs)class BookEditView(RetrieveUpdateDestroyAPIView):queryset = Book.objects.all()serializer_class = BookSerializerdef get(self, request, id, *args, **kwargs):return self.retrieve(request, id, *args, **kwargs)def patch(self, request, id, *args, **kwargs):return self.update(request, id, *args, **kwargs)def delete(self, request, id, *args, **kwargs):return sel