2

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/?

Tom Wojcik
  • 5,471
  • 4
  • 32
  • 44
DaveIdito
  • 1,546
  • 14
  • 31

1 Answers1

1

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.

Tom Wojcik
  • 5,471
  • 4
  • 32
  • 44
  • Hmm, I still get `Expected view ProfileRetrieveUpdate to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.` – DaveIdito May 02 '21 at 01:10