django rest framework ModelViewSet动态传入queryset和serializer_class,树形结构数据重复问题解决
需求背景:当继承ModelViewSet,视图层的类定义好之后,router.register注册类即可实现模型的增删改查,但有些业务逻辑需要根据前端传入参数动态改变queryset 和 serializer_class
需求背景:
当继承ModelViewSet,视图层的类定义好之后,router.register注册类即可实现模型的增删改查,
但有些业务逻辑需要根据前端传入参数动态改变 queryset 和 serializer_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_object和get_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的数据。
更多推荐
所有评论(0)