Skip to content

Commit 0dea78c

Browse files
authored
Merge pull request #1305 from tfranzel/pr1147
Pr1147
2 parents 09c5138 + 508a246 commit 0dea78c

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

drf_spectacular/plumbing.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,12 +536,18 @@ def safe_ref(schema: _SchemaType) -> _SchemaType:
536536

537537
def append_meta(schema: _SchemaType, meta: _SchemaType) -> _SchemaType:
538538
if spectacular_settings.OAS_VERSION.startswith('3.1'):
539+
schema = schema.copy()
540+
meta = meta.copy()
541+
539542
schema_nullable = meta.pop('nullable', None)
540543
meta_nullable = schema.pop('nullable', None)
541544

542545
if schema_nullable or meta_nullable:
543546
if 'type' in schema:
544-
schema['type'] = [schema['type'], 'null']
547+
if isinstance(schema['type'], str):
548+
schema['type'] = [schema['type'], 'null']
549+
else:
550+
schema['type'] = [*schema['type'], 'null']
545551
elif '$ref' in schema:
546552
schema = {'oneOf': [schema, {'type': 'null'}]}
547553
elif len(schema) == 1 and 'oneOf' in schema:

tests/test_extend_schema.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,54 @@ def test_extend_schema(no_warnings):
232232
)
233233

234234

235+
@mock.patch('drf_spectacular.settings.spectacular_settings.OAS_VERSION', '3.1.0')
236+
def test_extend_schema_field_with_dict_oas_3_1(no_warnings):
237+
@extend_schema_field({"type": "string"})
238+
class CustomField(serializers.CharField):
239+
pass
240+
241+
class XSerializer(serializers.Serializer):
242+
field1 = CustomField(read_only=True, allow_null=True)
243+
field2 = CustomField(read_only=True, allow_null=True)
244+
field3 = CustomField(read_only=True, allow_null=True)
245+
246+
@extend_schema(request=XSerializer, responses=XSerializer)
247+
@api_view(['POST'])
248+
def view_func(request, format=None):
249+
pass # pragma: no cover
250+
251+
schema = generate_schema('x', view_function=view_func)
252+
253+
assert schema['components']['schemas']['X']['properties'] == {
254+
'field1': {'readOnly': True, 'type': ['string', 'null']},
255+
'field2': {'readOnly': True, 'type': ['string', 'null']},
256+
'field3': {'readOnly': True, 'type': ['string', 'null']}
257+
}
258+
259+
260+
@mock.patch('drf_spectacular.settings.spectacular_settings.OAS_VERSION', '3.1.0')
261+
def test_extend_schema_field_with_schema_as_oas_3_1(no_warnings):
262+
@extend_schema_field({'type': ['string', 'integer']})
263+
class CustomField(serializers.CharField):
264+
pass
265+
266+
class XSerializer(serializers.Serializer):
267+
field1 = CustomField(read_only=True, allow_null=True)
268+
field2 = CustomField(read_only=True, allow_null=True)
269+
270+
@extend_schema(request=XSerializer, responses=XSerializer)
271+
@api_view(['POST'])
272+
def view_func(request, format=None):
273+
pass # pragma: no cover
274+
275+
schema = generate_schema('x', view_function=view_func)
276+
277+
assert schema['components']['schemas']['X']['properties'] == {
278+
'field1': {'readOnly': True, 'type': ['string', 'integer', 'null']},
279+
'field2': {'readOnly': True, 'type': ['string', 'integer', 'null']},
280+
}
281+
282+
235283
def test_layered_extend_schema_on_view_and_method_with_meta(no_warnings):
236284
class XSerializer(serializers.Serializer):
237285
field = serializers.IntegerField()

0 commit comments

Comments
 (0)