Django REST Framework add a ViewSet as detail on a

2019-07-06 01:13发布

问题:

I've got two models, one of a box and one of box comment:

class BoxViewSet(viewsets.ModelViewSet): queryset = Box.objects.all() permission_classes = IsAuthenticated, serializer_class = BoxSerializer

class BoxCommentViewSet(viewsets.ModelViewSet): model = BoxComment serializer_class = CommentSerializer permission_classes = IsAuthenticated def get_queryset(self): # this should return a queryset that filters based on the # box in the route return BoxComment.objects.all()

If I've set up a router to make Boxes available at /boxes/ and specific boxes available at /boxes/{id}/ using
router.register(r'boxes', feed.views.BoxViewSet)
is it possible to make comments available at /boxes/{id}/comments/? Or should I just set up a separate route and use GET/POST parameters to refer to specific boxes?

回答1:

This is typically referred to as nested routers (or nested viewsets), and it's generally not recommended in Django REST Framework. If possible, you should use a flat representation in your APIs, so

/boxes/{id}/comments

would actually be

/comments/?box={id}

This is considerably easier to implement with Django REST Framework using the built-in filtering (and maybe django-filter). It's guaranteed not to break in future versions of DRF, and it's the recommended way at the moment. The HTTP API guidelines might be a good read if you're interested why, and there's a discussion about it there as well.


Now, you can't always avoid using nested routers. I've written about it in the past, using the third-party packages that were available at the time. Since then, drf-extensions has integrated it and it contains a decent implementation of nested routers that should work for most cases.



回答2:

I don't see any problems to do this (I already use it in my projects and everything is fine) - all you need is an url with box_id kwarg. This has nothing with "nesting routers", it's just another endpoint with explicit filtering by url kwarg.

router.register(r'boxes/(?P<box_id>\d+)/comments', BoxCommentViewSet)

Then just filter out corresponding comments in get_queryset

class BoxCommentViewSet(viewsets.ModelViewSet):

    def get_queryset(self):
        return BoxComment.objects.filter(
            box=self.kwargs['box_id']
        )