奇怪的ModelViewSet行为

2024-06-28 20:46:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试用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\u id”。但是,get_queryset表示参数名是pk
  2. 第二个过滤器永远不起作用(应该返回给定父级的子级的过滤器)。DRF返回“detail”:“找不到”。如果在调试器中测试该行,它自然会返回给定父级的所有子级。你知道吗

我好像做错了什么,但代码对我来说太明显了,我就是看不见。你知道吗

一如既往,非常感谢您的帮助。你知道吗


Tags: 代码selfidreturnobjectsdrfclassqueryset
2条回答

关于1。您需要在viewset上设置lookup\u url\u kwarg(url中的命名参数),以便它映射到树id。

请注意,路由器本身确实定义了动态url部分。你知道吗

至于2。大多数情况下都是用表单内容类型发送JOSN POST数据。确保在请求的标头中发送正确的内容类型。你知道吗

编辑: 丹尼尔的观点是1。使用当前的url模式,无法区分详细的顶部节点和子节点的列表。你知道吗

结果,我一有机会就想忘记DefaultRouter的便捷功能。你知道吗

问题是,我想创建一个视图集,就像其他任何可写的视图集一样,但这个特定的视图集只用于检索项。至少,这是我的本意。但是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)

相关问题 更多 >