Django Rest Framework 中嵌套 URL 的相关资源

Related resources on a nested URL in Django Rest Framework

我有两个模型,FooBarBar 有一个指向 Foo 的外键。我有一个 FooModelViewSet,我想要路由 /api/foos/<pk>/bars/ 到 return 所有与给定 foo 相关的 bar

我知道这可以通过操作来完成。例如

class FooViewSet(viewsets.ModelViewSet):
    serializer_class = FooSerializer
    queryset = Foo.objects.all()

    @action(detail=True, methods=['GET'])
    def bars(self, request, pk):
        queryset = Bar.objects.filter(foo=pk)
        serializer = BarSerializer(queryset, many=True)
        return Response(serializer.data)

    @bars.mapping.post
    def create_bar(self, request, pk):
        request.data['foo'] = pk
        serializer = BarSerializer(request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

然而,这感觉像是很多不必要的样板代码。

不幸的是,使用 bars = PrimaryKeyRelatedField(many=True) 不适合我的情况,因为每个 foo 可以有数百个 bars,我不想在每个请求中发送。

是否可以更方便地在视图集中执行此操作?如果不是,正常的 DRF 方法是什么?具有不同 URL 的解决方案对我来说也是可以接受的,只要它最大限度地减少样板代码。

对我来说最直接的解决方案是对这个特定端点使用一个简单的 generics.ListAPIView

views.py

from rest_framework import generics


class FooBarsListAPIView(generics.ListAPIView):
    serializer_class = BarSerializer

    def get_queryset(self):
        return Bar.objects.filter(foo=self.kwargs.get('pk'))

然后您只需在 urls.py 而不是视图集中注册此视图。


为了达到您想要的结果,您需要做的就是这些。您只需指定查询集过滤器的外观,其他一切都由 ListAPIView 实现完成。

视图集在大多数情况下都可以完成工作,但如果您想要像这样的特定内容,视图集可能会变得矫枉过正。 是的,现在为这个特定端点定义了一个额外的 class,但样板代码减少到零,这正是我们最终想要的。