diff --git a/drf_spectacular/openapi.py b/drf_spectacular/openapi.py index 0aee6915..09e99264 100644 --- a/drf_spectacular/openapi.py +++ b/drf_spectacular/openapi.py @@ -951,9 +951,9 @@ def _get_response_for_code(self, serializer, status_code, media_types=None): name=paginated_name, type=ResolvedComponent.SCHEMA, schema=paginator.get_paginated_response_schema(schema), - object=paginated_name, + object=serializer, ) - self.registry.register(component) + self.registry.register_on_missing(component) schema = component.ref elif paginator: schema = paginator.get_paginated_response_schema(schema) diff --git a/drf_spectacular/plumbing.py b/drf_spectacular/plumbing.py index 47b32628..8708f749 100644 --- a/drf_spectacular/plumbing.py +++ b/drf_spectacular/plumbing.py @@ -437,7 +437,7 @@ def __init__(self): self._components = {} def register(self, component: ResolvedComponent): - if component.key in self._components: + if component in self: warn( f'trying to re-register a {component.type} component with name ' f'{self._components[component.key].name}. this might lead to ' @@ -446,7 +446,7 @@ def register(self, component: ResolvedComponent): self._components[component.key] = component def register_on_missing(self, component: ResolvedComponent): - if component.key not in self._components: + if component not in self: self._components[component.key] = component def __contains__(self, component): diff --git a/tests/test_regressions.py b/tests/test_regressions.py index cd8e09ad..60ba2de0 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -1029,6 +1029,31 @@ class XViewset(viewsets.ReadOnlyModelViewSet): assert substitution['properties']['results']['items']['$ref'] == '#/components/schemas/X' +def test_pagination_reusage(no_warnings): + class M7(models.Model): + pass + + class XSerializer(serializers.ModelSerializer): + class Meta: + fields = '__all__' + model = M7 + + class XViewset(viewsets.ReadOnlyModelViewSet): + queryset = M7.objects.all() + serializer_class = XSerializer + pagination_class = pagination.LimitOffsetPagination + + class YViewset(XViewset): + serializer_class = XSerializer + + router = routers.SimpleRouter() + router.register('x', XViewset, basename='x') + router.register('y', YViewset, basename='y') + generator = SchemaGenerator(patterns=router.urls) + schema = generator.get_schema(request=None, public=True) + validate_schema(schema) + + @mock.patch( 'drf_spectacular.settings.spectacular_settings.SECURITY', [{'apiKeyAuth': []}] diff --git a/tests/test_warnings.py b/tests/test_warnings.py index fb27b2ff..89273aaa 100644 --- a/tests/test_warnings.py +++ b/tests/test_warnings.py @@ -15,7 +15,7 @@ from tests import generate_schema -def test_serializer_name_reuse(warnings): +def test_serializer_name_reuse(capsys): from rest_framework import routers from drf_spectacular.generators import SchemaGenerator @@ -29,7 +29,7 @@ class XSerializer(serializers.Serializer): def x2(): class XSerializer(serializers.Serializer): - integer = serializers.IntegerField + integer = serializers.IntegerField() return XSerializer @@ -46,6 +46,9 @@ class X2Viewset(mixins.ListModelMixin, viewsets.GenericViewSet): generator = SchemaGenerator(patterns=router.urls) generator.get_schema(request=None, public=True) + stderr = capsys.readouterr().err + assert 'Encountered 2 components with identical names "X" and different classes' in stderr + def test_owned_serializer_naming_override_with_ref_name_collision(warnings): class XSerializer(serializers.Serializer):