奇怪的ModelViewSet行为

时间:2015-10-30 14:35:55

标签: python django django-rest-framework

我正在尝试使用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")

我对此代码有两个问题:

  1. 我在路由器注册中声明了参数“tree_id”。但是,get_queryset表示参数名称为pk
  2. 第二个过滤器永远不会起作用(应该返回给定父项的子项)。 DRF返回“详细信息”:“未找到。”。如果我在调试器中测试该行,它自然会返回给定父级的所有子级。
  3. 我似乎做错了什么,但代码对我来说似乎很明显,我只是看不到它。

    帮助 - 一如既往 - 非常感谢。

2 个答案:

答案 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模式,无法区分详细的顶级节点和子节点的列表。