Overriding Django REST ViewSet with custom post me

2019-03-11 06:48发布

问题:

I have a a ModelViewSet in Django's REST Framework that gives me the ability to do a POST and GET through the following address:

api/v1/users

These Users have a a reverse relation to a Comments table and I'd like to be able to access these Comments through the URL:

api/v1/users/<username>/comments

I was able to do this by setting up a custom @detail_route by overriding the queryset and and serializer_class but it only works for GET requests. If I attempt to POST a new comment through the REST Framework's admin section, I receive an error notice stating "'ListSerializer' object is not iterable"

Here's my code:

class UserViewSet(viewsets.ModelViewSet):
    queryset         = User.objects.all()
    serializer_class = UserFlat
    lookup_field     = 'username'


    @detail_route(methods=['post','get'])
    def comment(self, request, **kwargs):

        user = self.get_object()

        self.queryset         = Comment.objects.filter(recipient=user.id)
        self.serializer_class = CommentFlat

        serializer = CommentFlat(instance=self.queryset, many=True)

        return Response(serializer.data)

The new comment should take the following parameters:

comment.author, comment.message, comment.recipient

I can enter all those fields in the admin panel and attempt to create a post request but it fails. Ideally, I should only have to fill out comment.message and comment.author and the comment.recipient field should be autopopulated with user.id which is obtained in the url api/v1/users/<username>/comments

Does anyone know why my post request isn't completing and how I can autofill that one field?

回答1:

I figured it out. For those looking for an answer as well, the solution was to explicitly define the actions that occur when request.method == 'POST' and pass a the object into the serializer.

    @detail_route(methods=['post','get'])
    def comment(self, request, **kwargs):

        user = self.get_object()

        self.queryset = Comment.objects.filter(recipient=user.id)
        self.serializer_class = CommentFlat

        if request.method == 'POST':

            # request.data is from the POST object. We want to take these
            # values and supplement it with the user.id that's defined
            # in our URL parameter
            data = {
                'comment': request.data['comment'],
                'rating': request.data['rating'],
                'author': request.data['author'],
                'recipient': user.id
            }

            serializer = CommentFlat(data=data)

            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # Return GET by default
        else:

            serializer = CommentFlat(instance=self.queryset, many=True)

            return Response(serializer.data)