需求背景:
当继承ModelViewSet,视图层的类定义好之后,router.register注册类即可实现模型的增删改查,
但有些业务逻辑需要根据前端传入参数动态改变 querysetserializer_class, 其原因是model层将部分空值字段拆分为几个相似的表结构,而为了前端方便将相似的API接口整合为一个接口,通过传入不同类型请求。

实现方式
重写 get_queryset()方法和 get_serializer_class()方法
在这里插入图片描述
如创建,更新和删除方法也需要动态调整:
则重写 perform_create()、perform_update()和 perform_destroy()方法即可
或直接完全重写create,update,destroy 方法

还有一些情况是API接口返回树形结构遇到的 bug

Model:在这里插入图片描述
serializers:
在这里插入图片描述
views:
在这里插入图片描述

这样json返回将会出现二级,三级等数据重复出现在与一级平级的结构中,可能这并不是我们想要的结果
解决方式一
serializers中: get_child()方法过滤parent=None的数据

def get_child(self,obj):
        return DepartmentSerializer(obj.children.filter(parent=None),many=True).data

或者是在DepartmentView中的queryset过滤

queryset =  Department.objects.filter(parent=None)

这样虽然解决了list返回中没有重复,但是获取详情时会拿不到parent=None的数据
例 id=5的数据 parent为4
GET /api/department/5
在这里插入图片描述
这样对为一级目录的数据无法进行更新和删除

解决方法二:
在DepartmentView中重写 get_object(self)方法
DepartmentView代码如下:
在这里插入图片描述

可能存在问题:在实际开发过程中,有可能也存在自定义了get_objectget_queryset方法,
这样会导致如果get_queryset方法里的queryset返回的是过滤了parent=None的数据集,则获取非一级目录数据同样返回:
在这里插入图片描述

我们查看get_object源代码得知:
generics.py中的GenericAPIView类
在这里插入图片描述
看源代码知道get_object方法中的数据集来源是**get_queryset()**方法

如上所述,为了满足需求,我们需要继承GenericAPIView类重写get_object方法

最终解决方法:
如下图:
红框为改动地方,其它地方不变
在这里插入图片描述


最终 DepartmentView 代码如下

class DepartmentView(_GenericAPIView,viewsets.ModelViewSet):
    serializer_class = DepartmentSerializer

    def get_queryset(self):
        return Department.objects.filter(parent=None)

    def get_object(self):
        queryset = Department.objects.all()
        return super().get_object(queryset)

注意: 在DepartmentView中继承的类 _GenericAPIView写在viewsets.ModelViewSet前面
这样list列表返回是只返回一级目录,因为二三级目录一级包含嵌套已经在child字段中
获取列表中某个数据详情时,get_object的数据集是所有数据,所以可以返回parent=None的数据。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐