From 96a4f3884de849b71135b0c7f3efc7c3b9333d50 Mon Sep 17 00:00:00 2001 From: "T. Franzel" Date: Tue, 1 Oct 2024 23:50:25 +0200 Subject: [PATCH 1/2] add SerializerMethodField self-reference hint test --- tests/test_regressions.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 806e43f5..0dd53299 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -3421,3 +3421,26 @@ class XViewSet(viewsets.ReadOnlyModelViewSet): schema = generate_schema('/x', XViewSet) assert schema['paths']['/x/']['get']["operationId"] == 'list_x' assert schema['paths']['/x/{id}/']['get']["operationId"] == 'retrieve_x' + + +class SelfReferentialSerializer(serializers.Serializer): + field_int = serializers.IntegerField() + field_self = serializers.SerializerMethodField() + + def get_field_self(self) -> "SelfReferentialSerializer": + return SelfReferentialSerializer() # pragma: no cover + + +def test_self_referential_serializer_method_field(no_warnings): + class XViewset(viewsets.ModelViewSet): + serializer_class = SelfReferentialSerializer + queryset = SimpleModel.objects.all() + + schema = generate_schema('/x', XViewset) + assert schema['components']['schemas']['SelfReferential']['properties'] == { + 'field_int': {'type': 'integer'}, + 'field_self': { + 'allOf': [{'$ref': '#/components/schemas/SelfReferential'}], + 'readOnly': True + } + } From 8156c0bef161c44e4451be3ffd22fe0266d26a50 Mon Sep 17 00:00:00 2001 From: "T. Franzel" Date: Tue, 1 Oct 2024 23:51:22 +0200 Subject: [PATCH 2/2] fix OAS3.1 validator omission #1302 --- drf_spectacular/openapi.py | 4 ++++ tests/test_oas31.py | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drf_spectacular/openapi.py b/drf_spectacular/openapi.py index 12d6f274..ff0e5e36 100644 --- a/drf_spectacular/openapi.py +++ b/drf_spectacular/openapi.py @@ -1069,6 +1069,10 @@ def _map_basic_serializer(self, serializer, direction): def _insert_field_validators(self, field, schema): schema_type = schema.get('type') + # OAS 3.1 special case - extract the main type + if isinstance(schema_type, list): + schema_type = [t for t in schema_type if t != 'null'][0] + def update_constraint(schema, key, function, value, *, exclusive=False): if callable(value): value = value() diff --git a/tests/test_oas31.py b/tests/test_oas31.py index 9cdaa4cd..83ff6f9a 100644 --- a/tests/test_oas31.py +++ b/tests/test_oas31.py @@ -1,10 +1,11 @@ from unittest import mock -from rest_framework import serializers +from rest_framework import serializers, viewsets from rest_framework.views import APIView from drf_spectacular.utils import extend_schema from tests import generate_schema +from tests.models import SimpleModel @mock.patch('drf_spectacular.settings.spectacular_settings.OAS_VERSION', '3.1.0') @@ -68,3 +69,23 @@ def get(self, request): 'required': ['foo'], 'type': 'object' } + + +@mock.patch('drf_spectacular.settings.spectacular_settings.OAS_VERSION', '3.1.0') +def test_validator_addition_for_oas31(no_warnings): + + class XSerializer(serializers.Serializer): + field = serializers.CharField(allow_blank=True, allow_null=True, max_length=40, required=False) + + class XViewset(viewsets.ModelViewSet): + serializer_class = XSerializer + queryset = SimpleModel.objects.none() + + schema = generate_schema('x', XViewset) + + assert schema['components']['schemas']['X'] == { + 'properties': { + 'field': {'maxLength': 40, 'type': ['string', 'null']} + }, + 'type': 'object' + }