How to customize response api schema with drf-spectacular for Django Rest Framework [Solved]

141 Views Asked by At

I have a problem of customizing API schema.

Here is my case: I need to return a list of instances in my serializer with it's fields, but also there is supposed to be one common aggregation field, that accumulates those model instances in a list.

Here is the example of json structure:

{
  "comments_amount": 2,
  "comments": [
    {
      "id": 0,
      "card_id": 0,
      "user_id": 0,
      "text": "Comment",
      "created_at": "2024-02-24T09:07:43.946Z",
      "updated_at": "2024-02-24T09:07:43.946Z"
    },
     {
      "id": 1,
      "card_id": 0,
      "user_id": 0,
      "text": "Comment",
      "created_at": "2024-03-24T09:07:43.946Z",
      "updated_at": "2024-03-24T09:07:43.946Z"
    }
  ]
}

Here is my code for serializer:

class CommentResponseSerializer(serializers.ModelSerializer):
    parent_id = serializers.IntegerField(help_text=_("ID of parent comment"), min_value=0, required=False)
    card_id = serializers.IntegerField(help_text=_("Product's card ID"), min_value=0)
    user_id = serializers.IntegerField(help_text=_("ID of user who created this comment"), required=True)

    class Meta:
        model = Comment
        exclude = ["user", "parent", "card"]

And here is for views:

@extend_schema(tags=["Product Cards"], summary="API для комментариев карточек продуктов")
class CommentView(APIView):
    @extend_schema(
        description="API для просмотра комментариев. Доступно всем пользователям.",
        parameters=[
            OpenApiParameter(
                name="card_id", description="ID карточки продукта", required=True, type=int, location="path"
            )
        ],
        request=CommentInputSerializer,
        responses=CommentResponseSerializer,
    )
    def get(self, request, *args, **kwargs):
        card_id = kwargs["card_id"]
        comments = Comment.objects.filter(card_id=card_id)
        serializer = CommentResponseSerializer(comments, many=True)

        data = {
            "comments_amount": comments.count(),
            "comments": serializer.data
        }

        return Response(data, status=status.HTTP_200_OK)

Here, as you can see, I create dict with comments_amount field and commentsfield for comments themselves with help of CommentResponseSerializer. So how could I represent not only the CommentReponseSerializer fields, but also comments_amount field using drf-spectacular. I would be very grateful if someone helps. I have searched a lot, but did not find an appropriate solution.

1

There are 1 best solutions below

0
Mihail Bury On

After posting this question I came up with pretty simple and obvious solution. So, I created new serializer:

class CommentResponseWithAmountSerializer(serializers.Serializer):
    comments_amount = serializers.IntegerField(help_text=_("Amount of comments"))
    comments = CommentResponseSerializer(many=True, help_text=_("List of comments"))

    class Meta:
        fields = "__all__"

And updated view's get method:

@extend_schema(
    description="API для просмотра комментариев. Доступно всем пользователям.",
    parameters=[
        OpenApiParameter(
            name="card_id", description="ID карточки продукта", required=True, type=int, location="path"
        )
    ],
    request=CommentInputSerializer,
    responses=CommentResponseWithAmountSerializer,
)
def get(self, request, *args, **kwargs):
    card_id = kwargs["card_id"]
    comments = Comment.objects.filter(card_id=card_id)

    serializer = CommentResponseWithAmountSerializer(
        {
            "comments_amount": comments.count(),
            "comments": CommentResponseSerializer(comments, many=True).data
        }
    )

    return Response(serializer.data, status=status.HTTP_200_OK)