diff --git a/drf_spectacular/openapi.py b/drf_spectacular/openapi.py index a850b6f4..372879e3 100644 --- a/drf_spectacular/openapi.py +++ b/drf_spectacular/openapi.py @@ -1078,7 +1078,7 @@ def _get_response_for_code(self, serializer, status_code, media_types=None): if ( self._is_list_view(serializer) and get_override(serializer, 'many') is not False - and '200' <= status_code < '300' + and ('200' <= status_code < '300' or spectacular_settings.ENABLE_LIST_MECHANICS_ON_NON_2XX) ): schema = build_array_type(schema) paginator = self._get_paginator() diff --git a/drf_spectacular/settings.py b/drf_spectacular/settings.py index 0a2eae6f..cc3d5573 100644 --- a/drf_spectacular/settings.py +++ b/drf_spectacular/settings.py @@ -107,6 +107,12 @@ # the order they arrived. Accepts either True, False, or a callable for sort's key arg. 'SORT_OPERATION_PARAMETERS': True, + # @extend_schema allows to specify status codes besides 200. This functionality is usually used + # to describe error responses, which rarely make use of list mechanics. Therefore, we suppress + # listing (pagination and filtering) on non-2XX status codes by default. Toggle this to enable + # list responses with ListSerializers/many=True irrespective of the status code. + 'ENABLE_LIST_MECHANICS_ON_NON_2XX': False, + # Option for turning off error and warn messages 'DISABLE_ERRORS_AND_WARNINGS': False, diff --git a/tests/test_regressions.py b/tests/test_regressions.py index a95b07db..80420c5b 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -2027,7 +2027,7 @@ def get(self, request): } -def test_serializer_method_field_with_functools_partial(): +def test_serializer_method_field_with_functools_partial(no_warnings): class XSerializer(serializers.Serializer): foo = serializers.SerializerMethodField() bar = serializers.SerializerMethodField() @@ -2052,3 +2052,27 @@ def view_func(request, format=None): 'foo': {'type': 'string', 'format': 'date', 'readOnly': True}, 'bar': {'type': 'integer', 'readOnly': True} } + + +@mock.patch( + 'drf_spectacular.settings.spectacular_settings.ENABLE_LIST_MECHANICS_ON_NON_2XX', True +) +def test_disable_list_mechanics_on_non_2XX(no_warnings): + @extend_schema( + request=SimpleSerializer, + responses={ + 200: SimpleSerializer(many=True), + 400: SimpleSerializer(many=True), + } + ) + @api_view(['POST']) + def view_func(request, format=None): + pass # pragma: no cover + + schema = generate_schema('/x/', view_function=view_func) + assert get_response_schema(schema['paths']['/x/']['post'], status='200') == { + 'type': 'array', 'items': {'$ref': '#/components/schemas/Simple'} + } + assert get_response_schema(schema['paths']['/x/']['post'], status='400') == { + 'type': 'array', 'items': {'$ref': '#/components/schemas/Simple'} + }