diff --git a/drf_spectacular/plumbing.py b/drf_spectacular/plumbing.py index e3c1b1cc..497b4d53 100644 --- a/drf_spectacular/plumbing.py +++ b/drf_spectacular/plumbing.py @@ -1,5 +1,4 @@ import collections -import copy import functools import hashlib import inspect @@ -534,7 +533,10 @@ def append_meta(schema: _SchemaType, meta: _SchemaType) -> _SchemaType: if schema_nullable or meta_nullable: if 'type' in schema: - schema['type'] = [schema['type'], 'null'] + if isinstance(schema['type'], str): + schema['type'] = [schema['type'], 'null'] + else: + schema['type'] = [*schema['type'], 'null'] elif '$ref' in schema: schema = {'oneOf': [schema, {'type': 'null'}]} elif len(schema) == 1 and 'oneOf' in schema: diff --git a/tests/test_extend_schema.py b/tests/test_extend_schema.py index 9a561b9d..f142eef2 100644 --- a/tests/test_extend_schema.py +++ b/tests/test_extend_schema.py @@ -257,6 +257,29 @@ def view_func(request, format=None): } +@mock.patch('drf_spectacular.settings.spectacular_settings.OAS_VERSION', '3.1.0') +def test_extend_schema_field_with_schema_as_oas_3_1(no_warnings): + @extend_schema_field({'type': ['string', 'integer']}) + class CustomField(serializers.CharField): + pass + + class XSerializer(serializers.Serializer): + field1 = CustomField(read_only=True, allow_null=True) + field2 = CustomField(read_only=True, allow_null=True) + + @extend_schema(request=XSerializer, responses=XSerializer) + @api_view(['POST']) + def view_func(request, format=None): + pass # pragma: no cover + + schema = generate_schema('x', view_function=view_func) + + assert schema['components']['schemas']['X']['properties'] == { + 'field1': {'readOnly': True, 'type': ['string', 'integer', 'null']}, + 'field2': {'readOnly': True, 'type': ['string', 'integer', 'null']}, + } + + def test_layered_extend_schema_on_view_and_method_with_meta(no_warnings): class XSerializer(serializers.Serializer): field = serializers.IntegerField()