详解Django DRF框架中APIView、GenericAPIView、ViewSet区别
https://zhuanlan.zhihu.com/p/72527077
View->APIView->GenericAPIView->Mixin扩展类->子类视图
一、DRF类视图-APIView
APIView视图基类:
Django框架View类的子类,在View类的基础上封装了一些功能。
功能如下:
1. 视图request参数变成了Request类的对象,不再是Django原始HttpRequest类的对象;
request.data: 保存解析之后的请求体中数据,已经解析为了字典或类字典(QueryDict)。 request.POST|request.body|request.FILES
request.query_params: 保存解析之后的查询字符串。request.GET
2. 响应时可以统一返回Response类的对象,DRF框架会根据客户端请求头的`Accept`将响应数据转换为对应数据格式进行返回,默认返回json,仅支持html或json;
`Accept: text/html`:将响应数据转换为html进行返回
`Accept: applicaiton/json`:将响应数据转换为json进行返回
return Response(响应数据)
3. 异常处理:如果视图出现了未处理的异常,DRF框架会对异常进行处理,并将处理的错误响应返回给客户端;
4. 认证&权限&限流
二、类视图-GenericAPIView
GenericAPIView视图基类:
继承自APIView,在APIView类的基础上封装了一些功能。
class 类视图(GenericAPIView):
serializer_class = <序列化器类> #指明视图所使用的序列化器类;
queryset = <查询集> #指明视图所使用的查询集
功能如下:
1. 封装了操作序列化器的属性和方法:
方法:
get_serializer_class:获取视图所使用的序列化器类;
eg:如果根据不同的action动作使用不同的额序列化器,需要重写此方法;
#视图集对象.action:获取所有执行的操作
def get_serializer_class(self):
if self.action=="retrieve":
return BookDetailSerializer
return BookSerializer
get_serializer:创建一个视图所使用的序列化器类的对象;
从类属性serializer_class中获得serializer的序列化类,提供给Mixin扩展类使用。
2. 封装了查询数据库的属性和方法:
方法:
get_queryset:获取视图所使用的查询集,
群操作就走get_queryset()方法(包括群查,群增等)
get_object:从视图所使用的查询集中查询指定的对象(默认根据pk主键进行查询),
单操作就走get_object()方法(包括单查,单增等)
eg:重写get_queryset
#获取当前用户的登录地址
def get_queryset(self):
return UserAddress.objects.filter(user = self.request.user)
eg:重写get_object:
#1.获取URL传递过来的参数:id=self.kwargs['pk']
定义类视图之后,类视图对象有一个属性kwargs字典,保存从url地址中提取的所有命名参数;
#2.取到当前的用户对象:user = self.request.user
请求后台时前端header中携带token认证,在后台就可以用request 取到当前的用户对象;
def get_object(self):
user = self.request.user
goodsid=self.kwargs['pk']
userfav = UserFav.objects.filter(user=user, goods_id=goodsid).first()
return userfav
重写perform_create
#将购物车中所有物品结算(删除购物车并将物品移至订单表中)
def perform_create(self, serializer):
order = serializer.save() # 创建一笔订单
global order_sn
order_sn += 1
order.order_sn = '000000' + str(order_sn)
order.save()
shopcarts = ShoppingCart.objects.filter(user=self.request.user)
for shopcart in shopcarts:
orderGoods = OrderGoods()
orderGoods.goods_num = shopcart.nums
orderGoods.goods = shopcart.goods
orderGoods.order = order
orderGoods.save()
# delete
shopcart.delete()
3. 过滤&分页
pagination_class 分页控制类
filter_backends 过滤控制后端
三、类视图-Mixin扩展类的功能&使用
继承自GenericAPIView之后,使用GenericAPIView中提供的操作序列化器的函数和数据库查询的函数写出的代码变成了通用代码,这些通用代码抽取之后,就是DRF框架提供的5个Mixin扩展类。
Mixin扩展类:
ListModelMixin(群查):list,封装了获取一组数据通用流程。
#除了查询,该list方法会对数据进行过滤和分页
CreateModelMixin(单增):create,封装了新增一条数据通用流程。
#注意:没有群增的方法,需要自己手动写(******)
RetrieveModelMixin(单查):retrieve,封装了获取指定数据通用流程。
UpdateModelMixin(更新,修改):update,封装了更新指定数据通用流程。
#只有单整体改和单局部改,没有群整体改和群局部改
DestroyModelMixin(删除):destroy,封装了删除指定数据通用流程。
视图 作用 可使用方法 父类 ListAPIView 查询多条数据 get GenericAPIView ListModelMixin CreateAPIView 新增一条数据 post GenericAPIView CreateModelMixin RetrieveAPIView 查询一条数据 get GenericAPIView RetrieveModelMixin UpdateAPIView 修改一条数据 put,patch GenericAPIView UpdateModelMixin DestroyAPIView 删除一条数据 delete GenericAPIView DestroyModelMixin RetrieveUpdateAPIView 单查,更新一条数据 get,put,patch GenericAPIView RetrieveModelMixin UpdateModelMixin RetrieveUpdateDestroyAPIView 单查,更新,删除一条数据 get,put,patch,delete GenericAPIView RetrieveModelMixin UpdateModelMixin DestroyModelMixin ListCreateAPIView 群查,更新一条 get,post
四、视图集-ViewSet视图集的功能&使用
视图集:将操作同一组资源的处理函数放在同一个类中,这个类就是视图集。
视图集和类视图的区别?
答:实现同一组接口时,如果使用类视图可能需要多个类视图,而使用视图集时只需要一个视图集。
比如:实现图书管理的5个接口时,使用类视图用了2个类视图:BookListVIew和BookDetailView,如果使用视图集只需要一个即可。
基本使用:
1. 继承自ViewSet(继承自ViewSetMixin和APIView)
2. 视图集中的处理函数不再以请求方式(比如:get,post等)命名,而是以对应的action操作命名,常见操作如下:
ListModelMixin:获取一组数据
createModelMixin:创建一条数据
retrieveModelMixin:获取指定数据
updateModelMixin:修改指定数据
destroyModelMixin:删除指定数据
3. 在urls.py进行url地址配置时需要明确指明某种请求方式请求某个地址对应的是视图集中的哪个处理函数。
五、视图集-视图集父类GenericViewSet使用
继承自ViewSetMixin和GenericAPIView,可以配合Mixin扩展类提供对应的处理函数
1)工具视图都是GenericAPIView的子类,且不同的子类继承了不同的工具类
2)工具视图的功能可以满足需求,只需要继承工具视图,并且提供queryset与serializer_class即可
GenericViewSet通常配合Mixin扩展类进行使用。
class TestViewSet(ListModelMixin, GenericViewSet):
serializer_class=""
queryset=""
六、视图集-视图集父类ModelViewSet和ReadOnlyModelViewSet使用
ModelViewSet:继承了5个Mixin扩展类,同时继承了GenericViewSet
ReadOnlyModelViewSet:继承了ListModelMixin, RetireveModelMixin,同时继承了GenericViewSet
需求:
写一个视图集,提供一下2个API接口:
1. 获取所有的图书 GET /books/ -> list
2. 获取指定的图书 GET /books/(?P<pk>\d+)/ -> retrieve
class BookInfoViewSet(ReadOnlyModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
七、视图集比较
1.常用视图集父类
ViewSet
继承自APIView和ViewSetMixin,没有提供任何方法,需要自己写
GenericViewSet
继承GenericAPIView和ViewSetMixin,其中GenericAPIView提供了基础方法,可以直接搭配Mixin扩展类使用,所以我们选这个
ModelViewSet
继承GenericViewset,但同时也包括ListModelMixin、CreateModelMixin等mixin扩展类
1)视图集都是默认优先继承ViewSetMixin类,再继承一个视图类(GenericAPIView或APIView)
2)ViewSetMixin提供了重写的as_view()方法,继承视图集的视图类,配置路由时调用as_view()必须传入 请求名-函数名 映射关系字典
eg: url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
表示get请求会交给my_get_list视图函数处理
八、路由Router
作用:动态生成视图集中处理函数的url配置项。
使用:
1. 创建Router类的对象
#DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
router = SimpleRouter()
router = DefaultRouter()
2. 注册视图集
router.register(<prefix>, <viewset>, <base_name>)
例如:router.register('books', views.BookInfoViewSet, base_name='books')
3. 将动态生成的配置项列表添加到urlpatterns中
方法一:urlpatterns += router.urls
方法二:urlpatterns = [
path(r'^', include(router.urls)),
]
方法三:urlpatterns.extend(router.urls)
九、常见问题
1.GenericAPIView与APIView两大继承视图的区别
1)GenericViewSet和ViewSet都继承了ViewSetMixin,as_view都可以配置 请求-函数 映射
2)GenericViewSet继承的是GenericAPIView视图类,用来完成标准的 model 类操作接口
3)ViewSet继承的是APIView视图类,用来完成不需要 model 类参与,或是非标准的 model 类操作接口
post请求在标准的 model 类操作下就是新增接口,登陆的post不满足
post请求验证码的接口,不需要 model 类的参与
案例:登陆的post请求,并不是完成数据的新增,只是用post提交数据,得到的结果也不是登陆的用户信息,而是登陆的认证信息
2.类视图和视图集区别?
答:实现同一组接口时,如果使用类视图可能需要多个类视图,而使用视图集时只需要一个视图集。
比如:实现图书管理的5个接口时,使用类视图用了2个类视图:BookListVIew和BookDetailView,如果使用视图集只需要一个即可。