Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oas31 validator fix #1304

Merged
merged 2 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
23 changes: 22 additions & 1 deletion tests/test_oas31.py
Original file line number Diff line number Diff line change
@@ -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')
Expand Down Expand Up @@ -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'
}
23 changes: 23 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Loading