Django-drf-视图家族合集
概述
在drf中,一般使用CBV(class-base-view)去写视图层的功能,在原生的Django中,使用FBV(function-base-view)较多,不过,即使是写CBV,底层实现也是FBV
所有视图的关系总结
View:Django中字典的原生的类,后续所有的类都是来自于它,是一个基类
APIView:继承自View,在drf中,所有的视图类,都来自于它,是一个基类,和View最大的区别就是重写了as_view方法,是drf中视图的起源
若继承APIView去写对应的接口的话,那么每一个接口都需要手动去写,获取数据、序列化等
GenericAPIView:继承自APIView,和APIView的区别就是,封装了query_set和serializer_class,写接口的时候,指定了这两个参数,那么查询数据使用对象的方法即可,不需要写ORM语句了,如self.get_object() 查询一条、self.get_query_set() 获取所有等
5个扩展类:CreateModelMixin、ListModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin
这5个扩展类没有继承任何类,是5个基类,使用时,可以仅继承它们,如继承ListModelMixin,不过极其不推荐使用,把接口写复杂了,因为ListModelMixin是没有as_view方法的,单单继承这个类,不如直接写一个FBV的函数,这个类的内部也只是封装了ORM的操作而已
所以组合最好的是GenericAPIView,写接口时,指定queryset和serializer_class,然后返回扩展类对应的方法即可
9个视图子类:ListAPIView、CreateAPIView、DestroyAPIView、UpdateAPIView、RetrieveAPIView、ListCreateAPIView、RetrieveDestroyAPIView、RetrieveUpdateAPIView、RetrieveUpdateDestroyAPIView
是5个视图扩展类结合GenericAPIView得到的类,写接口时,指定queryset和serializer_class即可,不需要再写方法了,除非这9个没有想要的功能,那就需要单独的写接口
视图集:ViewSetMixin、ViewSet、GenericViewSet、ModelViewSet、ReadOnlyModelViewSet
最主要的就是ViewSetMixin,重写了as_view方法,改变了路由的写法,请求方式对应对应的方法名即可
ModelViewSet是方法最全的类,如果这里没有需要的功能,那就需要自己写方法来实现
两个视图基类:View、APIView
一般仅在原生的Django中,才会使用到View,所以这里暂不展开,仅针对APIView,且由于与数据库交互较多,所以序列化器使用ModelSerializer
模型表、配置文件、序列化器准备
模型表
class Book(models.Model): name = models.CharField(max_length=32, verbose_name='书名') price = models.DecimalField(max_digits=5, decimal_places=2) author = models.CharField(max_length=32, verbose_name='作者') publish = models.CharField(max_length=32, verbose_name='出版社信息')
序列化器
from rest_framework import serializers from . import models class BookModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__'
修改配置
# 注册app # 配置数据库,导入pymysql # 国际化配置
APIView
使用APIView写5个接口,每一个方法都需要手动地写。
from rest_framework.views import APIView
from rest_framework.response import Response
路由配置
urlpatterns = [ path('book/', views.BookAPIView.as_view()), re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()), ]
查询所有
class BookAPIView(APIView): # 查询所有 def get(self, request, *args, **kwargs): # 1 获取数据 book_list = models.Book.objects.all() # 2 序列化数据 book_ser = serializer.BookModelSerializer(instance=book_list, many=True) # 3 返回序列化后的数据 return Response(book_ser.data)
新增一条
class BookAPIView(APIView):# 增加一条 def post(self,request,*args,**kwargs): # 直接序列化,不需要去数据库查询 book_ser = serializer.BookModelSerializer(data=request.data) # 校验 if book_ser.is_valid(): # 校验通过,保存数据 book_ser.save() # 根据RESTFul规范,返回创建后的数据 return Response(book_ser.data) else: # 未通过校验 return Response(book_ser.errors)
查询一条
class BookDetailAPIVIew(APIView): # 查询一条 def get(self,request,pk,*args,**kwargs): # 1 查询数据 print(pk) book = models.Book.objects.filter(pk=pk).first() # 2 序列化 book_ser = serializer.BookModelSerializer(instance=book) # 3 返回数据 return Response(book_ser.data)
修改一条
class BookDetailAPIVIew(APIView): # 修改一条 def put(self,request,pk,*args,**kwargs): # 1 查询数据 book = models.Book.objects.filter(pk=pk).first() # 2 序列化 book_ser = serializer.BookModelSerializer(instance=book,data=request.data) # 3 判断合法性,并保存数据 if book_ser.is_valid(): book_ser.save() return Response(book_ser.data) else: return Response(book_ser.errors)
删除一条
class BookDetailAPIVIew(APIView):# 删除一条 def delete(self,request,pk,*args,**kwargs): # 直接删除即可 models.Book.objects.filter(pk=pk).delete() return Response({"msg":"删除成功!"})
GenericAPIView
使用GenericAPIView写4个接口,GenericAPIView和APIView的区别就是,定义了query_set和serializer_class
删除接口和APIView一样
路由配置
urlpatterns = [ path('book/', views.BookAPIView.as_view()), re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()), ]
查询所有
class BookAPIView(GenericAPIView): queryset = models.Book.objects.all() # 建议带上 .object.all(),否则后面可能会报错 serializer_class = serializer.BookModelSerializer # 查询所有 def get(self,reuqest,*args,**kwargs): # 1 查询所有数据 book_list = self.get_queryset() # 2 序列化 book_ser = self.get_serializer(book_list,many=True) # 3 返回数据 return Response(book_ser.data)
新增一条
class BookAPIView(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer# 新增一条 def post(self,request,*args,**kwargs): # 获取数据,并序列化 book_ser = self.get_serializer(data=request.data) # 校验 if book_ser.is_valid(): # 保存数据 book_ser.save() return Response(book_ser.data) else: return Response(book_ser.errors)
查询一条
class BookDetailAPIVIew(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer def get(self,request,pk,*args,**kwargs): # 获取数据 book = self.get_object() # 获取单条数据用get_object # 序列化 book_ser = self.get_serializer(instance=book) # 返回数据 return Response(book_ser.data)
修改一条
class BookDetailAPIVIew(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializerdef put(self,request,*args,**kwargs): book = self.get_object() book_ser = self.get_serializer(instance = book,data=request.data) if book_ser.is_valid(): book_ser.save() return Response(book_ser.data) else: return Response(book_ser.errors)
删除一条
class BookDetailAPIVIew(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializerdef delete(self,request,pk,*args,**kwargs): # models.Book.objects.filter(pk=pk).delete() self.get_object().delete() return Response({"msg":"删除成功"})
GenericAPIView的5个扩展类
总共5个扩展类:
CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
使用的时候要结合GenericAPIVIew,因为这5个扩展类没有继承任何的类,就是一个基类,没有as_view方法,所以必须结合使用,建议将GenericAPIView写到第一个位置
基于GenericAPIView的5个扩展类,写上述5个接口
路由配置
urlpatterns = [ path('book/', views.BookAPIView.as_view()), re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()), ]
查询所有
class BookAPIView(GenericAPIView, ListModelMixin): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer # 查询所有 def get(self, request, *args, **kwargs): return self.list(request)
新增一条
class BookAPIView(GenericAPIView, CreateModelMixin): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer# 新增一条 def post(self, request, *args, **kwargs): return self.create(request)
查询一条
class BookDetailAPIVIew(GenericAPIView,RetrieveModelMixin): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer # 查询一条 def get(self, request, pk, *args, **kwargs): return self.retrieve(request, pk)
更新一条
class BookDetailAPIVIew(GenericAPIView,RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
# 修改一条
def put(self, request, pk, *args, **kwargs):
return self.update(request, pk)
删除一条
class BookDetailAPIVIew(GenericAPIView,RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer # 删除一条 def delete(self, request, pk, *args, **kwargs): return self.destroy(request, pk)
GenericAPIView的9个视图子类
来源
这9个视图子类是GenericAPIView结合GenericAPIView的5个扩展类,将get post put delete进一步封装得到的类,在使用时,只需要指定queryset和serializer_class即可
class ListAPIView(mixins.ListModelMixin, GenericAPIView): # 查询所有 class CreateAPIView(mixins.CreateModelMixin, GenericAPIView): # 新建一条 class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView): # 删除一条 class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView): # 修改一条 class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): # 查询所有、创建一条 class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView): # 查询一条 class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView): # 查询一条、删除一条 class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView): # 查询一条、修改一条 class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView): # 查询一条、修改一条、删除一条
路由配置
urlpatterns = [ path('book/', views.BookAPIView.as_view()), re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()), ]
查询所有、新增一条
from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView class BookAPIView(ListAPIView, CreateAPIView): # 仅需要继承对应的类,不需要写get、post方法 queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer
查询一条、修改一条、删除一条
from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView class BookDetailAPIVIew(DestroyAPIView, RetrieveAPIView, UpdateAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer
除了这5个常见的外,还有多个组合的,仅需要继承对应的类就可以了
视图集
来源
通过重写ViewSetMixin这个魔法类的as_view方法,重新定义了路由的写法,同时结合GenericAPIVie和其扩展类,写了视图集
ViewSetMixin(重写了as_view,提供了新的路由写法)
ViewSet(什么都没有,路由换了写法)
GenericViewSet(主要是继承了GenericAPIView)
ModelViewSet(方法是最全的,在路由写GenericAPIView的扩展类的方法名即可)
ReadOnlyModelViewSet(仅查询使用)
class ViewSetMixin: # 魔法类,重写了as_view方法,继承了这个类,那么路由就要写成这样:MyViewSet.as_view({'get': 'list', 'post': 'create'}) class ViewSet(ViewSetMixin, views.APIView): # 视图集基类,不提供任何方法,方法需要手动写,路由写法也是action:方法,写法类似于APIView,只不过路由是新写法 class GenericViewSet(ViewSetMixin, generics.GenericAPIView): # 路由是新写法,同时有了queryset、serializer_class class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): # 继承了GenericAPIView的5个扩展类,直接返回这5个扩展类的方法即可,同时继承了GenericViewSet class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet): # 继承了查询一条和所有的GenericAPIView的扩展类和GenericViewSet
通过ModelViewSet写5个接口
使用ModelViewSet的愿意是,这个类继承了GenericAPIView的扩展类,方法是最多的,实现相应的功能只需要在路由中写入对应即可
视图层
from rest_framework.viewsets import ModelViewSet class BookAPIView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer
路由层
带不带id值都可以写在一个视图类中,在路由层做区分即可
urlpatterns = [ path('admin/', admin.site.urls), # 基础的视图类 # path('book/', views.BookAPIView.as_view()), # re_path('book/(?P<pk>\d+)', views.BookDetailAPIVIew.as_view()), # 视图集合 path('book/', views.BookAPIView.as_view(actions={'get': 'list', 'post': 'create'})), re_path('book/(?P<pk>\d+)', views.BookAPIView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), ]
浙公网安备 33010602011771号