DRF的视图
APIView
Django中写CBV的时候继承的是View,rest_framework继承的是APIView,
urlpatterns = [ url(r'^book$', BookView.as_view()), # url(r'^book/(?P<id>d+)', BookEditView.as_view()), 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"})), ]
View和APIView调用的都as_view()方法,我们知道APIView继承了View,并且重写了as_view()方法,并执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。看下图:
APIView还执行了dispatch方法,新的request是Request类的实例化对象,看下图:
我们看看initialize_request中的代码实现了什么功能:
点击Request可以看到Request类把原来的request赋值给了self._request,也就是说以后_request是我们旧的request,看下图:
继承APIVIew之后的请求来的数据,看下图:
当用了rest_framework框架后,我们的request是重新封装的Request类
request.query_params存放的是我们get请求的参数
request.data存放的是我们所有的数据,包括post请求的以及put,patch请求
相比原来的Django的request,我们现在的request更加精简,清晰了
由于我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码
所以我们需要封装一下。
第一次封装
因为代码中除了序列化器不同以及获取的queryset对象不同,其他的都类似。所有我们它相同的代码封装出来,提高代码的复用性。
APIView视图
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("删除的书籍不存在")
第一次封装
from django.shortcuts import render from rest_framework.views import APIView from djangoDemo.models import Book from .serializers import BookSerializer from rest_framework.response import Response # queryset不同 # 序列化器不同 # def get(): # def post(): class GenericAPIView(APIView): queryset = None serializer_class = None def get_queryset(self): # 放到缓存中再拿出来时就需要我们用all()来获取,这是Django机制导致的 return self.queryset.all() def get_serializer(self, *args, **kwargs): return self.serializer_class(*args, **kwargs) class ListModelMixin(object): def list(self, request): # 调用外部的get方法 # 执行父类的方法 queryset = self.get_queryset() # 实例化序列化器 ser_obj = self.get_serializer(queryset, many=True) return Response(ser_obj.data) class CreateModelMixin(object): def create(self, request): ser_obj = self.get_serializer(data=request.data) if ser_obj.is_valid(): ser_obj.save() # 校验过的数据存放在validated_data中 return Response(ser_obj.validated_data) return Response(ser_obj.errors) class RetrieveModelMixin(object): def retrieve(self, request, id): book_obj = self.get_queryset().filter(id=id).first() ser_obj = BookSerializer(book_obj) return Response(ser_obj.data) class UpdateModelMixin(object): def update(self, request, id): book_obj = self.get_queryset().filter(id=id).first() ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True) if ser_obj.is_valid(): ser_obj.save() # 去反序列化以后的数据中去找到并返回 return Response(ser_obj.validated_data) return Response(ser_obj.errors) class DestroyModelMixin(object): def destroy(self, request, id): book_obj = self.get_queryset().filter(id=id).first() if not book_obj: return Response('删除的数据不存在') book_obj.delete() return Response('') class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request): # 封装ListModelMixin类以后的执行过程 return self.list(request) # 只封装GenericAPIView类的执行过程 # # 调用外部的get方法 # # 执行父类的方法 # queryset = self.get_queryset() # # 实例化序列化器 # ser_obj = self.get_serializer(queryset, many=True) # return Response(ser_obj.data) # 没封装之前 # book_queryset = Book.objects.all() # 用序列化器进行序列化 # ser_obj = BookSerializer(book_queryset, many=True) # 通过点data来获取数据 # return Response(ser_obj.data) # 没封装前的post执行过程 # def post(self, request): # # 获取从前端传递过来的值 # book_obj = request.data # # data=book_obj就是反序列化时的对象数据 # ser_obj = BookSerializer(data=book_obj) # if ser_obj.is_valid(): # ser_obj.save() # # 反序列化以后的数据放在validated_data中 # return Response(ser_obj.validated_data) # # 如果校验不成功则返回错误信息 # return Response(ser_obj.errors) # 继承CreateModelMixin类后的post执行过程 def post(self, request): return self.create(request) class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, id): # book_obj = Book.objects.filter(id=id).first() # ser_obj = BookSerializer(book_obj) # return Response(ser_obj.data) return self.retrieve(request, id) def put(self, request, id): # book_obj = Book.objects.filter(id=id).first() # ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True) # if ser_obj.is_valid(): # ser_obj.save() # # 去反序列化以后的数据中去找到并返回 # return Response(ser_obj.validated_data) # return Response(ser_obj.errors) return self.update(request, id) def delete(self, request, id): # book_obj = Book.objects.filter(id=id).first() # if not book_obj: # return Response('删除的数据不存在') # 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): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request): # 封装ListModelMixin类以后的执行过程 return self.list(request) # 继承CreateModelMixin类后的post执行过程 def post(self, request): return self.create(request) class BookEditView(RetrieveUpdateDestroyAPIView): 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.destroy(request, id)
第三次封装
我们可不可以把这两个视图合并成一个视图呢~~~框架给我们提供了一个路由传参的方法~~
actions这个默认参数其实就是我们路由可以进行传参了~~~
下面这个循环~可以看出~我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法~
这样我们每个视图就不用在写函数了~因为已经和内部实现的函数相对应了~
路由urls.py
from django.conf.urls import url, include from .views import BookView, BookEditView, BookModelView # 帮助我们生成带参数的路由 from rest_framework.routers import DefaultRouter # 实例化DefaultRouter对象 router = DefaultRouter() # 注册我们的路由以及视图 router.register(r'^book', BookModelView) urlpatterns = [ url(r'^book$', BookView.as_view()), # url(r'^book/(?P<id>d+)', BookEditView.as_view()), 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"})), ] urlpatterns += router.urls
第三次封装
ViewSetMixin 重写了as_view()方法
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 from rest_framework.viewsets import ViewSetMixin from rest_framework import views # APIView from rest_framework import viewsets from rest_framework import generics from rest_framework import mixins # 自定义了一个类, class ModelViewSet(ViewSetMixin, ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin): pass # 然后继承它 class BookModelView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
由于第三次封装所以路由发生了改变:
from django.conf.urls import url, include from .views import BookView, BookEditView, BookModelView urlpatterns = [ url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})), url(r'^book/(?P<pk>d+)/', BookModelView.as_view({"get": "list", "post": "create", "put": "update", "delete": "destroy"})), ]
注意一点~~用框架封装的视图~我们url上的那个关键字参数要用pk~~系统默认的~~
看看我们的继承顺序
DRF的路由
路由
from django.conf.urls import url, include from .views import BookView, BookEditView, BookModelView # 帮我们生成带参数的路由(我们原本是不能传递参数的在路由中) from rest_framework.routers import DefaultRouter # 实例化DefaultRouter对象 router = DefaultRouter() # 注册我们的路由以及视图 router.register(r'book', BookModelView) urlpatterns = [ # url(r'^book/$', BookView.as_view()), # url(r'^book/(?P<pk>d+)/', BookEditView.as_view()), # url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})), # url(r'^book/(?P<pk>d+)/', # BookModelView.as_view({"get": "list", "post": "create", "put": "update", "delete": "destroy"})), ] urlpatterns += router.urls
需要自定制的时候还是需要我们自己用APIView写~~当不需要那么多路由的时候~也不要用这种路由注册~~