APIView和View的区别
不管是View还是APIView最开始调用的都是as_view()
APIView继承了View, 并且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。
在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类
我们用了rest_framework框架以后,我们的request是重新封装的Request类
request.query_params 存放的是我们get请求的参数
request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求
相比原来的django的request,我们现在的request更加精简,清晰了
现在我们知道了APIView和View的一些区别
视图的第一次封装
GenericAPIView 是对 APIView 的封装
xxxMixin 是对处理的各种请求方法的封装
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.data book_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视图
from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from .serializers import BookSerializer class GenericAPIView(APIView): query_set = None serializer_class = None def get_queryset(self): return self.query_set def get_serializer(self, *args, **kwargs): return self.serializer_class(*args, **kwargs) class ListModelMixin(object): def list(self, request): queryset = self.get_queryset() ret = self.get_serializer(queryset, many=True) return Response(ret.data) class CreateModelMixin(object): def create(self, request): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) else: return Response(serializer.errors) class RetrieveModelMixin(object): def retrieve(self, request, id): book_obj = self.get_queryset().filter(id=id).first() ret = self.get_serializer(book_obj) return Response(ret.data) class UpdateModelMixin(object): def update(self, request, id): book_obj = self.get_queryset().filter(id=id).first() serializer = self.get_serializer(book_obj, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data) else: return Response(serializer.errors) class DestroyModelMixin(object): def destroy(self, request, id): book_obj = self.get_queryset().filter(id=id).first() book_obj.delete() return Response("") class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass # class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): class BookView(ListCreateAPIView): query_set = Book.objects.all() # 操作的表的对象 serializer_class = BookSerializer # 序列化的类 def get(self, request): # book_obj = Book.objects.first() # ret = BookSerializer(book_obj) # book_list = Book.objects.all() # book_list = self.get_queryset() # ret = self.get_serializer(book_list, many=True) # return Response(ret.data) return self.list(request) def post(self, request): # print(request.data) # serializer = BookSerializer(data=request.data) # if serializer.is_valid(): # serializer.save() # return Response(serializer.data) # else: # return Response(serializer.errors) return self.create(request) # class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): class BookEditView(RetrieveUpdateDestroyAPIView): query_set = Book.objects.all() serializer_class = BookSerializer def get(self, request, id): # book_obj = Book.objects.filter(id=id).first() # ret = BookSerializer(book_obj) # return Response(ret.data) return self.retrieve(request, id) def put(self, request, id): # book_obj = Book.objects.filter(id=id).first() # serializer = BookSerializer(book_obj, data=request.data, partial=True) # if serializer.is_valid(): # serializer.save() # return Response(serializer.data) # else: # return Response(serializer.errors) return self.update(request, id) def delete(self, request, id): # book_obj = Book.objects.filter(id=id).first() # book_obj.delete() # return Response("") return self.destroy(request, id)
视图的第二次封装
class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass class BookView(ListCreateAPIView): pass class BookEditView(RetrieveUpdateDestroyAPIView): pass
# 上面我们写的继承类太长了~~我们再改改 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, *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 = BookSerializer def 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 self.delete(request, id, *args, **kwargs) 第二次封装
视图的第三次封装
ViewSetMixin
actions这个默认参数其实就是我们路由可以进行传参了
下面这个循环,可以看出,我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法
这样我们每个视图就不用在写函数了,因为已经和内部实现的函数相对应了
因为是按照请求的方式不同反回的结果,所有第二次有两个视图函数
现在指定一个视图函数
# 视图类传参,不同的请求对应不同的方法 path('list', BookModelViewSet.as_view({"get": "list", "post": "create"})), path('retrieve/<int:pk>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
注意一点,用框架封装的视图,我们url上的那个关键字参数要用pk,系统默认的
# class ViewSetMixin(object): # def as_view(self): # """ # 按照我们参数指定的去匹配 对应的方法 # get-->list # :return: 不用我们去写,框架有 # """
ViewSetMixin 请求分发方法的原理,将不同的请求设置为不同的方法
from rest_framework.viewsets import ViewSetMixin # class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): # queryset = Book.objects.all() # serializer_class = BookSerializer # 如果我们再定义一个类 class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): pass class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer 第三次封装
from rest_framework.viewsets import ViewSetMixin class ModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass # from rest_framework.viewsets import ModelViewSet # 框架内部已经实现了的,可以直接导入 # class BookModelViewSet(ModelViewSet):
query_set = Book.objects.all() 自己封装的query_set
# queryset = Book.objects.all() # 框架的是queryset
serializer_class = BookSerializer
from rest_framework import views # APIView
from rest_framework import generics # GenericAPIView, 组合类
from rest_framework import mixins #混合继承类
from rest_framework import viewsets # ViewSetMixin 分发请求的类
我们现在的视图就只要写两行就可以了
用框架的时
路由为
path('retrieve/<int:pk>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
前面自己定义的是id,用框架时注意修改过来
path('retrieve/<int:id>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
# 视图类传参.只有业务需求匹配性很强才用。通常情况下不这么用容易暴露接口 # path('list', BookModelViewSet.as_view({"get": "list", "post": "create"})), # path('retrieve/<int:id>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
继承顺序
DRF的路由
from django.urls import path, include from .views import BookView, BookEditView, BookModelViewSet from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r"", BookModelViewSet) # 不能 加$ r"$" urlpatterns = [ # path('list', BookView.as_view()), # path('retrieve/<int:id>', BookEditView.as_view()), # 视图类传参.只有业务需求匹配性很强才用。通常情况下不这么用容易暴露接口 # path('list', BookModelViewSet.as_view({"get": "list", "post": "create"})), # path('retrieve/<int:id>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), ] urlpatterns += router.urls DefaultRouter
通过框架我们可以把路由视图都变的非常简单,但是需要自定制的时候还是需要我们自己用APIView写
当不需要那么多路由的时候,也不要用这种路由注册
总之,一切按照业务需要去用