前后端分离djangorestframework——视图组件
CBV与FBV
CBV之前说过就是在view.py里写视图类,在序列化时用过,FBV就是常用的视图函数,两者的功能都可以实现功能,但是在restful规范方面的话,CBV更方便,FBV还要用request.method来判断是get,put,post等的,在CBV里要用什么就定义什么方法,根据请求的方法自动进入对应的CBV的方法里,节省了判断请求类型的过程
View与APIView
APIView就是在View上做了二次封装,多了一些功能而已,View是django自带的视图组件
在 前后端分离djangorestframework——序列化与反序列化数据 这篇文章中(所以接下来用到的数据还是这篇文章里用到的数据),利用了DRF的序列化与反序列化,感受了下DRF的特性,但其实视图部分的代码还是有点冗余,假如以后有上百个url,就要给上百个url写对应的视图类,然后对数据的增删改查,都要重写一次,这样功能是可以实现,但是太low了,需要改善下
View的第一次改版
每次在重复书写的是数据库表的操作,序列化类的操作,以及不同的请求方式对应的视图类的方法,所以可以微调一下:
修改数据库表和序列化类,重新定义一个类,代替操作,此后这个GenericView类可以被所有的视图类继承了,简直是一劳永逸的
再重组请求方式对应的方法:
访问页面看有没有问题:
添加一个字段看看:
成功:
可能你访问list时还没看到数据,打开数据库库查看是有的,多刷新几次页面就有了:
好的,把剩下的对单调数据操作的也改了
全部代码:
# coding:utf-8 from django.shortcuts import HttpResponse from django.views import View from demo1 import models from django.core import serializers from rest_framework.views import APIView from rest_framework.response import Response from demo1.serializers import BookSerializer class OldBookView(View): # def get(self, request): # book_list = models.Book.objects.values("id", "title", 'pub_time','publisher') # book_list = list(book_list) # ret = [] # for field in book_list: # pub_id = field['publisher'] # publish_obj = models.Publisher.objects.filter(id=pub_id).first() # field['publisher'] = { # 'id':pub_id, # 'title':publish_obj.title # } # ret.append(field) # # return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) def get(self, request): book_list = models.Book.objects.all() ret = serializers.serialize('json', book_list, ensure_ascii=False) return HttpResponse(ret) 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) # Mixin字段的都是混合类,需要混合继承 class ListModelMixin(object): def list(self, request): book_list = self.get_queryset() ret = self.get_serializer(book_list, many=True) return Response(ret.data) class CreateModelMixin(object): def create(self, request): serialize = self.get_serializer(data=request.data) if serialize.is_valid(): # save是存储 serialize.save() return Response(serialize.data) else: return Response(serialize.errors) class BookView(GenericAPIView, CreateModelMixin, ListModelMixin): query_set = models.Book.objects.all() serializer_class = BookSerializer def get(self, request): # 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): # serialize = self.get_serializer(data=request.data) # if serialize.is_valid(): # serialize.save() # return Response(serialize.data) # else: # return Response(serialize.errors) return self.create(request) class RetrieveModelMixin(object): def list(self, request, id): book_obj = self.get_queryset().filter(id=id).first() ret = self.get_serializer(book_obj) return Response(ret.data) class RetrieveUpdateModelMixin(object): def update(self, request, id): book_obj = self.get_queryset().filter(id=id).first() # partial参数表示只对部分数据验证 serialize = self.get_serializer(book_obj, data=request.data, partial=True) if serialize.is_valid(): serialize.save() return Response(serialize.data) else: return Response(serialize.errors) class RetrieveDestoryModelMixin(object): def destory(self, request, id): book_obj = self.get_queryset().filter(id=id).exists() if not book_obj: return Response('不存在id为%s的数据,请重试' % id) else: self.get_queryset().filter(id=id).delete() return Response("删除成功") class BookEditView(GenericAPIView, RetrieveModelMixin, RetrieveUpdateModelMixin, RetrieveDestoryModelMixin): query_set = models.Book.objects.all() serializer_class = BookSerializer def get(self, request, id): # book_obj = models.Book.objects.filter(id=id).first() # ret = BookSerializer(book_obj) # return Response(ret.data) return self.list(request, id) def put(self, request, id): # book_obj = models.Book.objects.filter(id=id).first() # # partial参数表示只对部分数据验证 # serialize = BookSerializer(book_obj, data=request.data, partial=True) # # if serialize.is_valid(): # # print(serialize.validated_data) # # save是存储 # serialize.save() # return Response(serialize.data) # else: # return Response(serialize.errors) return self.update(request, id) def delete(self, request, id): # book_obj = models.Book.objects.filter(id=id).exists() # if not book_obj: # return Response('不存在id为%s的数据,请重试' % id) # else: # models.Book.objects.filter(id=id).delete() # return Response("删除成功") return self.destory(request, id)
访问:
修改:
删除:
没有问题
View的第二次改版
有几个视图类继承好多个类,再次微调,再定义两个类只是继承那些类,然后视图类再继承此类,相对刚才没有做任何改动,就多了一个中间父类而已
View的第三次改版
还有个问题,看url,都是对Book表的操作,但是却有两个视图类来处理,不太符合restful规范
修改url,给as_view添加一个字典参数,但是默认as_view是不可以传参的,所以我们需要自己封装一个可以传参的类
补充,我传的as_view参数中,对单条数据修改的retrieve的get方式由之前的"get":"list"已经改成了'get':'retrieve',对应的自定义RetrieveMixin里的方法也由list改成了retrieve,因为和上面对多条数据的"get":"list" 重复了,为了防止报错,所以修改了
定义类,修改as_view传参:
具体的逻辑代码就不写了,因为DRF自带了
直接用DRF定义的View——ModelViewSet
view.py文件,ModelViewSet用的不是query_set而是queryset,需要改下:
url要做稍微的调整,ModelViewSet用的是pk,还得把id改为pk:
好的其他不用作任何更改
访问:
添加:
修改:
删除:
数据库里已经没有id为7的
是的,就是这么方便
全部代码:
url:
from django.urls import path, re_path, include # from demo1.views import BookView, BookEditView, BookModelViewSet from demo1.views import BookModelViewSet urlpatterns = [ path('list', BookModelViewSet.as_view({'get': 'list', 'post': 'create'})), path('retrieve/<int:pk>', BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), ]
view:
# coding:utf-8 from demo1 import models from demo1.serializers import BookSerializer from rest_framework.viewsets import ModelViewSet class BookModelViewSet(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookSerializer
当然,如果你还是想用自己定义那些方法类,可以这样:
全部代码:相关的类名做了稍微的调整
# coding:utf-8 from django.shortcuts import HttpResponse from django.views import View from demo1 import models from django.core import serializers from rest_framework.views import APIView from rest_framework.response import Response from demo1.serializers import BookSerializer from rest_framework.viewsets import ViewSetMixin 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) # Mixin字段的都是混合类,需要混合继承 class ListModelMixin(object): def list(self, request): book_list = self.get_queryset() ret = self.get_serializer(book_list, many=True) return Response(ret.data) class CreateModelMixin(object): def create(self, request): serialize = self.get_serializer(data=request.data) if serialize.is_valid(): # save是存储 serialize.save() return Response(serialize.data) else: return Response(serialize.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 RetrieveUpdateModelMixin(object): def update(self, request, id): book_obj = self.get_queryset().filter(id=id).first() # partial参数表示只对部分数据验证 serialize = self.get_serializer(book_obj, data=request.data, partial=True) if serialize.is_valid(): serialize.save() return Response(serialize.data) else: return Response(serialize.errors) class RetrieveDestoryModelMixin(object): def destroy(self, request, id): book_obj = self.get_queryset().filter(id=id).exists() if not book_obj: return Response('不存在id为%s的数据,请重试' % id) else: self.get_queryset().filter(id=id).delete() return Response("删除成功") class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, RetrieveUpdateModelMixin, RetrieveDestoryModelMixin): pass class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class BookView(ListCreateAPIView): query_set = models.Book.objects.all() serializer_class = BookSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request) class BookEditView(RetrieveUpdateDestroyAPIView): query_set = models.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) class ModelViewSet(ViewSetMixin, ListModelMixin, CreateModelMixin, RetrieveUpdateModelMixin, RetrieveModelMixin, RetrieveDestoryModelMixin): pass class BookModelViewSet(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookSerializer
视图组件完毕!
然后,有些东西是需要看源码才能看懂的,相关的源码查看:
from rest_framework import views from rest_framework import generics from rest_framework import mixins from rest_framework import viewsets
整个逻辑示图: