drf-spectacular

Django spectacular 'could not derive type of path parameter "id"' when there is no such parameter


In my Django project, I have this URL definition

router.register(
    r"device-types/(?P<device_type_id>[\d\w-]+)/variants/(?P<variant_id>[\d\w-]+)/accessible-sub-paths",
    AccessibleSubPathViewSet,
    basename="accessible-sub-paths",
)

Note that the parameters are device_type_id and variant_id.

The referenced viewset is

class AccessibleSubPathViewSet(viewsets.ModelViewSet):
    """
    API for accessible sub paths.

    Permissions:
    - [UserIsOperator,]
    """

    serializer_class = AccessibleSubPathSerializer
    permission_classes = (custompermissions.UserIsOperator,)

    def get_queryset(self):
        return AccessibleSubPath.objects.filter(variant=self.kwargs["variant_id"])

And the serializer is

class AccessibleSubPathSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.AccessibleSubPath
        fields = (
            "id",
            "schema_path",
        )
        read_only_fields = ("id",)

When I run spectacular to generate the openapi spec, I get this warning

/code/django/devices/viewsets.py:146: Warning [AccessibleSubPathViewSet]: could not derive type of path parameter "id" because it is untyped and obtaining queryset from the viewset failed. Consider adding a type to the path (e.g. <int:id>) or annotating the parameter type with @extend_schema. Defaulting to "string".

But "id" is not a path parameter—it's a serializer field.

How do I clear this warning?


Solution

  • The answer is that spectacular infers the /{id} parameter for the retrieve operation in ModelViewSet. Specifying the types using extend_schema clears the warning, like this

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name="device_type_id",
                type=OpenApiTypes.UUID,
                location=OpenApiParameter.PATH,
            ),
            OpenApiParameter(
                name="variant_id",
                type=OpenApiTypes.UUID,
                location=OpenApiParameter.PATH,
            ),
            OpenApiParameter(
                name="id",
                type=OpenApiTypes.UUID,
                location=OpenApiParameter.PATH,
            ),
        ],
    )
    class AccessibleSubPathViewSet(viewsets.ModelViewSet):
        """
        API for accessible sub paths.
    
        Permissions:
        - [UserIsOperator,]
        """
    
        serializer_class = AccessibleSubPathSerializer
        permission_classes = (custompermissions.UserIsOperator,)
    
        def get_queryset(self):
            return AccessibleSubPath.objects.filter(variant=self.kwargs["variant_id"])