drf-spectacular
drf-spectacular copied to clipboard
[Bug] Custom Pagination Class with get_paginated_response_schema does not work when there are 2 view with same serializer
Describe the bug Hello! I wanted to use my custom pagination and override the schema. I've searched and found that such issue is already taken care of #1048
However, I was not be able to reproduce the same outcome When item in paginated response is similar to another paginated response. No longer what I do with get_paginated_response_schema. It does not change the out come of how my swagger is generated
To Reproduce You have 2 view using the 2 different paginated response with the same serializer class.
Have your second custom pagination class and override get_paginated_response_schema. I even try the extreme method in returning empy dictionary
The 1st pagination class
class CustomCursorPagination(CursorPagination):
ordering = "-created_at"
page_size = 20
page_size_query_param = "page_size"
The view
class GeneralTradeOrderViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
permission_classes = (GeneralTradeOrderPolicy,)
queryset = Order.objects.all()
pagination_class = CustomCursorPagination
filter_backends = [django_filters.DjangoFilterBackend, filters.SearchFilter]
filterset_class = OrderFilterSet
search_fields = ["id", "wholesale__name"]
def get_serializer_class(
self,
) -> Type[OrderListSerializer | OrderDetailGetSerializer]:
if self.action == "list":
return OrderListSerializer
return OrderDetailGetSerializer
2nd Pagination and view
class MyCursorPagination(CursorPagination):
ordering = "-created_at"
page_size = 20
page_size_query_param = "page_size"
def get_paginated_response_schema(self, schema: Any) -> dict:
print("IN MY PAGINATED RESPONSE")
return {}
put your pagination class inside view
class WholesaleOrderViewSet(viewsets.ModelViewSet):
permission_classes = (WholesaleOrderPolicy,)
queryset = Order.objects.all()
pagination_class = MyCursorPagination
def get_serializer_class(
self,
) -> Type[OrderListSerializer | OrderDetailGetSerializer | EditOrderRequestSerializer]:
if self.action == "list":
return OrderListSerializer
elif self.action == "update":
return EditOrderRequestSerializer
return OrderDetailGetSerializer
As you can see, both class are using different pagination class but with the same serializer class.
then when you retrieve swagger. The 2nd class with empty dictionary response for schema still produces default response for pagination with correct serializer
I use a debugging tool and found out that, somehow, in openapi.py
when it calls get_paginated_response
the result schema is still correct order item
function then call in openapi.py but schema value is not empty dictionary
And when I commented out the pagination for 1st view.
class GeneralTradeOrderViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
permission_classes = (GeneralTradeOrderPolicy,)
queryset = Order.objects.all()
# pagination_class = CustomCursorPagination
The schema is generated correctly for the 2nd view.
Expected behavior The generated schema should be what's in the get_paginated_response_schema
I am not sure if I'm missing some basic steps but this is what I can gather so far.
Hi,
spectacular assumes that you only use one paginator for each individual serializer. Otherwise you have a naming collision, and that is what is likely producing your incorrect schema.
You need to create a custom AutoSchema, set it in the settings, and override this method to prevent collisions:
https://github.com/tfranzel/drf-spectacular/blob/21c4e05b8f1c2fb8c47f9d586c6bac8fa31b971d/drf_spectacular/openapi.py#L1146-L1147
You could call this a bug, but I'm not sure how to solve this for everyone, because choosing a good name is not trivial.
That's good to know! I was suspecting it has something to do with the serializer but didn't think of AutoSchema could potentially see 2 different paginator class as being the same.
Thank you for the help and the fast response! 🎉