tfranzel/drf-spectacular

Unable to extend schema for UpdateAPIView

stefanofusai opened this issue · 2 comments

Describe the bug
As pointed in the title, I am unable to extend the schema for my UpdateAPIView

To Reproduce
Here is the code of the User and UserSetting views: the first one gets extended correctly, while the second one doesn't

class UserAPIView(RetrieveAPIView):
    serializer_class = UserResponseSerializer
    permission_classes = [...]

    def get_object(self) -> User:
        return self.request.user

    @extend_schema(  # type: ignore[arg-type,type-var]
        operation_id="user",
        parameters=[...],
        summary="Retrieve user data",
    )
    def get(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        serializer = self.get_serializer(self.get_object())
        return Response(serializer.data)


class UserSettingAPIView(UpdateAPIView):
    serializer_class = UserSettingResponseSerializer
    permission_classes = [...]

    def get_object(self) -> UserSetting:
        return UserSetting.objects.get(user=self.request.user)

    @extend_schema(  # type: ignore[arg-type,type-var]
        operation_id="user-settings",
        parameters=[...],
        summary="Update user settings",
    )
    def update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        serializer = self.get_serializer(
            self.get_object(), data=request.data, partial=True
        )
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

Expected behavior
As you can see in the following screenshot, the PUT/PATCH endpoints don't include the summary I specified. Furthermore, they don't include the parameters (which I omitted in the code above) nor the specified operation_id.
Am I doing anything wrong? Should I move to a ViewSet?

image

https://drf-spectacular.readthedocs.io/en/latest/faq.html#using-extend-schema-on-apiview-has-no-effect

class UpdateAPIView(mixins.UpdateModelMixin,
                    GenericAPIView):
    """
    Concrete view for updating a model instance.
    """
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

You need to decorate the put/patch method, as update is only DRF's syntactic sugar and not the actual entrypoint.

That worked perfectly! Thank you as always for the help and sorry for not reading through the docs first.