Skip to content

Commit

Permalink
Merge pull request #1110 from tfranzel/openapi_request_fix
Browse files Browse the repository at this point in the history
bugfix ignored OpenApiRequest case #1106
  • Loading branch information
tfranzel authored Nov 18, 2023
2 parents fbbcab3 + 4994a4b commit ad7e4a0
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 31 deletions.
59 changes: 29 additions & 30 deletions drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import copy
import functools
import itertools
import re
import typing
from collections import defaultdict
Expand Down Expand Up @@ -1252,42 +1253,40 @@ def _get_request_body(self, direction='request'):
return None

request_serializer = self.get_request_serializer()
request_body_required = True
content = []

# either implicit media-types via available parsers or manual list via decoration
if isinstance(request_serializer, dict):
content = []
request_body_required = True
for media_type, serializer in request_serializer.items():
if isinstance(serializer, OpenApiRequest):
serializer, examples, encoding = (
serializer.request, serializer.examples, serializer.encoding
)
else:
encoding, examples = None, None
media_types_iter = request_serializer.items()
else:
media_types_iter = zip(self.map_parsers(), itertools.repeat(request_serializer))

if (
encoding
and media_type != "application/x-www-form-urlencoded"
and not media_type.startswith('multipart')
):
warn(
'Encodings object on media types other than "application/x-www-form-urlencoded" '
'or "multipart/*" have undefined behavior.'
)
for media_type, serializer in media_types_iter:
if isinstance(serializer, OpenApiRequest):
serializer, examples, encoding = serializer.request, serializer.examples, serializer.encoding
else:
encoding, examples = None, None

schema, partial_request_body_required = self._get_request_for_media_type(serializer, direction)
examples = self._get_examples(serializer, direction, media_type, None, examples)
if schema is None:
continue
if (
encoding
and media_type != "application/x-www-form-urlencoded"
and not media_type.startswith('multipart')
):
warn(
'Encodings object on media types other than "application/x-www-form-urlencoded" '
'or "multipart/*" have undefined behavior.'
)

examples = self._get_examples(serializer, direction, media_type, None, examples)
schema, partial_request_body_required = self._get_request_for_media_type(serializer, direction)

if schema is not None:
content.append((media_type, schema, examples, encoding))
request_body_required &= partial_request_body_required
else:
schema, request_body_required = self._get_request_for_media_type(request_serializer, direction)
if schema is None:
return None
content = [
(media_type, schema, self._get_examples(request_serializer, direction, media_type), None)
for media_type in self.map_parsers()
]

if not content:
return None

request_body = {
'content': {
Expand Down
3 changes: 2 additions & 1 deletion drf_spectacular/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
'APPEND_PATHS': {},
'APPEND_COMPONENTS': {},

# DISCOURAGED - please don't use this anymore as it has tricky implications that
# STRONGLY DISCOURAGED (with the exception for the djangorestframework-api-key library)
# please don't use this anymore as it has tricky implications that
# are hard to get right. For authentication, OpenApiAuthenticationExtension are
# strongly preferred because they are more robust and easy to write.
# However if used, the list of methods is appended to every endpoint in the schema!
Expand Down
13 changes: 13 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3226,3 +3226,16 @@ class X2ViewSet(viewsets.ReadOnlyModelViewSet):
'type': 'array',
'items': {'$ref': '#/components/schemas/Simple'}
}


def test_openapirequest_used_without_media_type_dict(no_warnings):
@extend_schema(request=OpenApiRequest(SimpleSerializer), responses=None)
@api_view(['POST'])
def view_func(request, format=None):
pass # pragma: no cover

schema = generate_schema('/x/', view_function=view_func)

assert get_request_schema(schema['paths']['/x/']['post']) == {
'$ref': '#/components/schemas/Simple'
}

0 comments on commit ad7e4a0

Please sign in to comment.