DaveIdito
DaveIdito

Reputation: 1606

How to send PUT request to ModelViewSet without passing a primary key in the url?

I am particularly interested in using ModelViewSet for solving the challenge of updating the logged in user's profile. I am using the following definition:

from rest_framework import viewsets

class ProfileRetrieveUpdate(viewsets.ModelViewSet):
    serializer_class = UserProfileSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def get_queryset(self):
        return UserProfile.objects.filter(user=self.request.user)

    def perform_update(self, serializer):
        serializer.save(user=self.request.user)

By overriding get_queryset, I am able to get the expected behavior, i.e. when I access the endpoints (say profile/), I get the profile of the logged in user. However, if I have to update the profile, I can only access PUT by going to profile/6/. Is there a way I can get ModelViewSet to expose PUT at the same endpoint i.e. profile/?

Upvotes: 2

Views: 1955

Answers (1)

Tom Wojcik
Tom Wojcik

Reputation: 6189

You can register ModelViewSet HTTP method under any path you want.

path(
    "profile",
    ProfileRetrieveUpdate.as_view(
        {"put": "partial_update", "get": "retrieve"}
    ),
    name="profile-retrieve-update",
)

You will have to adjust other things as well as you don't provide pk. Instead of overriding get_queryset method you need to adjust get_object for your needs.

from rest_framework import viewsets
from rest_framework.generics import get_object_or_404


class ProfileRetrieveUpdate(viewsets.ModelViewSet):
    serializer_class = UserProfileSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = UserProfile.objects.all()

    def get_object(self):
        obj = get_object_or_404(self.queryset, user=self.request.user)
        self.check_object_permissions(self.request, obj)
        return obj

    def perform_update(self, serializer):
        serializer.save(user=self.request.user)

Now if you PUT profile/ it should work as expected.

Upvotes: 1

Related Questions