我正在尝试使用DRF序列化MPTT树模型。
我的代码:
class SiteTreeCalc(serializers.Field):
def to_representation(self, value):
return value.exists() # return True if has children, False otherwise
class SiteTreeSerializer(serializers.ModelSerializer):
children = SiteTreeCalc()
class Meta:
model = SiteTree
fields = ('id', 'site', 'children')
depth = 1
class SiteTreeViewSet(viewsets.ModelViewSet):
#queryset = SiteTree.objects.all()
serializer_class = SiteTreeSerializer
def get_queryset(self):
if 'pk' not in self.kwargs:
# return first-level nodes
return SiteTree.objects.filter(level=0)
else:
# return all children of a given node
return SiteTree.objects.filter(parent__id=int(self.kwargs['pk']))
router = routers.DefaultRouter()
router.register(r'rest/sitetree', SiteTreeViewSet, "SiteTreeRoots")
router.register(r'rest/sitetree/(?P<tree_id>\d+)/$', SiteTreeViewSet, "SiteTreeChildren")
我对此代码有两个问题:
get_queryset
表示参数名称为pk
我似乎做错了什么,但代码对我来说似乎很明显,我只是看不到它。
帮助 - 一如既往 - 非常感谢。
答案 0 :(得分:1)
事实证明,我想在第一次机会中忘记DefaultRouter的便捷功能。
问题在于我想像任何其他可写ViewSet一样创建一个ViewSet,但这个特定的ViewSet仅用于检索项目。至少,这就是我的意图。但DRF无法知道,所以我的问题#2是DRF实际检查我返回的一个项目与URL中给出的pk完全相同的结果。
有效的解决方案就像这样(建议in the DRF ViewSets documentation):
class SiteTreeViewSet(viewsets.ReadOnlyModelViewSet):
queryset = SiteTree.objects.filter(level=0)
serializer_class = SiteTreeSerializer
@detail_route()
def children(self, request, pk=None):
data = SiteTree.objects.filter(parent__id=int(pk))
data = self.get_serializer(data, many=True)
return Response(data.data)
此解决方案以默认模式返回第一级项目,并接受/{pk}/children
以返回给定pk节点的子级。当然,当提供/{pk}/
URL时,默认操作仍将仅返回pk节点。
路由器注册仅保留默认值:
router.register(r'rest/sitetree', SiteTreeViewSet)
答案 1 :(得分:0)
至于1.您需要在视图集上设置lookup_url_kwarg(URL中的命名参数),以便映射到tree_id。
请注意,路由器会自行定义动态网址部分。
至于2.它大部分时间发送带有表单内容类型的JOSN POST数据。确保您在请求的标题中发送了正确的内容类型。
编辑: Daniel指出1.使用您当前的url模式,无法区分详细的顶级节点和子节点的列表。