Swagger provide correct render of POST method API from serializer, but not for DELETE method

Viewed 2521

Our project is using Django, Django-Rest-Framework, and drf_yasg to document our API with swagger. I created a serializer, and I'm using it with my POST method. everything works well, all the fields are present on my swagger page. I created a delete method using the same serializer and the swagger documentation is showing as parameters to the API only the first group of fields.

I tried to use

@swagger_auto_schema(
    method='post',
    operation_description="POST /Rules/list/",
    responses={200: listResponseSerializer()},
)
@swagger_auto_schema(
@swagger_auto_schema(responses={200: listResponseSerializer()})
    method='delete',
    operation_description="DELETE /Rules/list/",
    responses={200: listResponseSerializer()},
)
@action(detail=False, methods=['post', 'delete'])

and have a single method. both, the post and delete methods are immediately absent from the documentation page.

and when using @swagger_auto_schema(responses={200: listResponseSerializer()})

Post method is working, but not the delete method.

this capture shows the good results from POST method, where all the fields are presents in the API documentation. filters, parameters, and others.

enter image description here

With DELETE, it shows only the filters and ignores all the other fields present in the serializer.

enter image description here

Hope someone can help me with this one. I'm struggling for a couple of days now with it. I don't catch what I'm missing or what piece of the integration between django and swagger I don't understand, and need help.

views.py:

    class ActionAPIView(generics.GenericAPIView):
        """
        Base class for all Action views so the filtering is automatically inserted

        """
        filter_class = RESTRuleFilter

        def get_queryset(self):
            return Rule.objects.allowed_to_user(self.request.user)

        def filter_queryset(self, queryset):
            serializer = self.get_serializer(data=self.request.data)
            if serializer.is_valid():
                if 'filter' in serializer.validated_data:
                    filter = RESTRuleFilter(serializer.validated_data['filter'], queryset=queryset)
                    return filter.qs

            return queryset

        def get_serializer(self, *args, **kwargs):
            return listSerializer(*args, **kwargs)


    class listItemsApi(ActionAPIView):
        """
        post:
            add one or more Items to selected Rule list

        delete:
            remove one or more Items to selected Rule list

        """
        def get_queryset(self):
            return Rule.objects.allowed_to_user(self.request.user)

        def get_serializer(self, *args, **kwargs):
            return listPostSerializer(*args, **kwargs)

        def get_delete_serializer(self, *args, **kwargs):
            return listSerializer(*args, **kwargs)

        def get_channel(self, list_id):
            bu_list = []
            for i in list_id:
                bu = Channel.objects.allowed_to_user(self.request.user).get(
                    pk=i
                )
                bu_list.append({"pk": bu.id, "name": bu.name})

            return bu_list



        @swagger_auto_schema(responses={200: listResponseSerializer()})
        def post(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())
            serializer = self.get_serializer(data=request.data)

            if serializer.is_valid():
                selected_Rules = serializer.get_selected_Rules(queryset)
                bu_ids, cluster_list, Rules_id = self.build_sets(selected_Rules)
                bu = self.get_channel(bu_ids)

                task_id, timestamp = "sample_task_001"


                response = {
                    "channels": bu,
                    "task_id": task_id,
                }

                return Response(response, status=status.HTTP_200_OK)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

in serializer.py:

    class listItemsSerializer(serializers.Serializer):
        block_item = serializers.CharField(required=False, allow_blank=True)
        never_log_item = serializers.BooleanField(required=False, default=False)
        never_learn_item = serializers.BooleanField(required=False, default=False)
        description = serializers.CharField(required=False, allow_blank=True)



    class listFiltersSerializer(serializers.Serializer):
        name = serializers.CharField(required=False, allow_blank=True)
        cluster = serializers.CharField(required=False, allow_blank=True)
        channel = serializers.CharField(required=False, allow_blank=True)
        partition = serializers.CharField(required=False, allow_blank=True)


    class listSerializer(serializers.Serializer):
        filters = listFiltersSerializer(required=False, help_text="list of Rules filters")
        items = serializers.ListField(child=serializers.CharField(), required=True)
        selected = serializers.ListField(child=serializers.IntegerField(), required=False, write_only=True)

        select_all = serializers.BooleanField(
            default=False,
            write_only=True,
            help_text=("Set to True to select all objects"),
        )

        def validate(self, data):
            """
            Check if either both selected_status and select_all are configured or 
            we have a list of selected entries in selected
            """
            user = get_current_user()
            if data["select_all"]:
                return data

            if data["select_all"] is False and (
                "selected" not in data or not data["selected"]
            ):
                raise serializers.ValidationError(
                    "You must specify either select_all or selected"
                )

            found_count = 0
            if "selected" in data and data["selected"]:
                for d in data["selected"]:
                    if Rule.objects.allowed_to_user(user).filter(pk=d).exists():
                        found_count += 1

                if found_count != len(data["selected"]):
                    raise serializers.ValidationError(
                        "Some of the selected items are invalid"
                    )

            return data

        def get_selected_Rules(self, queryset=None):
            if queryset is None:
                queryset = Rule.objects.all()

            if self.validated_data.get('select_all', False):
                return queryset
            else:
                return queryset.filter(pk__in=self.validated_data['selected'])


    class listPostSerializer(listSerializer):
        params = listItemsSerializer(
            required=True, help_text="list of Itemss and setting to apply on selected Rules"
        )

filters.py:

    class RESTRuleFilter(RESTFilterSet):
        name = django_filters.CharFilter(
            lookup_expr="icontains", help_text="Rule name containing"
        )
        cluster = django_filters.ModelMultipleChoiceFilter(
            queryset=Cluster.objects.all()
        )
        channel = django_filters.ModelMultipleChoiceFilter(
            queryset=Channel.objects.all(), method="subfilter"
        )
        partition = django_filters.CharFilter(
            lookup_expr="icontains", help_text="Partition name containing"
        )
        enforcement_mode = django_filters.CharFilter(
            lookup_expr="icontains",
            label="Enforcement Mode",
            help_text="Enforcement Mode  containing",
        )
        signatureset_name = django_filters.CharFilter(
            label="Rule containing a signature set matching this string",
            field_name="signatureset",
            method="subfilter",
        )

        class Meta:
            model = Rule
            fields = (
                "name",
                "cluster",
                "channel",
                "partition",
                "xxxxxxx",
                "yyyyyyy",
            )

urls.py:

    schema_view = get_schema_view(
        openapi.Info(
            title="WAF Management Portal API",
            default_version="v1",
            description="REST api for interaction between Frontend and Backend.",
            contact=openapi.Contact(email="xxx@email.com"),
        ),
        public=True,
        permission_classes=(permissions.AllowAny,),
    )

    urlpatterns = [
        path(
            "",
            schema_view.with_ui("swagger", cache_timeout=0),
            name="schema-swagger-ui",
        ),
        path(
            "rule/", ruleListAPIView.as_view(), name="rule_list_view_api"
        ),
        path(
            "rules/list/", listItemsApi.as_view(), name="list_api"
        ),

    ]

models.py:

    class Channel(models.Model):
        name = models.CharField(max_length=1024, db_index=True, unique=True)

    class Cluster(models.Model):
        name = models.CharField(max_length=1024, db_index=True, unique=True)
        channel = models.ForeignKey(
            Channel, on_delete=models.SET_NULL, null=True
        )

    class rule(models.Model):
        app_id = models.CharField(max_length=32, db_index=False)
        cluster = models.ForeignKey(
            Cluster, on_delete=models.CASCADE, related_name="rules", null=True
        )
        name = models.CharField(max_length=1024, db_index=True)
        partition = models.CharField(max_length=128, db_index=True)

        objects = ruleManager()

        class Meta:
            verbose_name_plural = "rules"
            unique_together = ("app_id", "cluster")
            indexes = [models.Index(fields=["app_id", "cluster"])]

        def __str__(self):
            return self.full_path
0 Answers
Related