Skip to content

Commit 0e7954d

Browse files
knivetscarltongibson
authored andcommitted
Schemas: Map renderers/parsers for request/response media-types.
1 parent 1cc4be4 commit 0e7954d

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

rest_framework/schemas/openapi.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import warnings
2+
from operator import attrgetter
23
from urllib.parse import urljoin
34

45
from django.core.validators import (
@@ -8,7 +9,7 @@
89
from django.db import models
910
from django.utils.encoding import force_str
1011

11-
from rest_framework import exceptions, serializers
12+
from rest_framework import exceptions, renderers, serializers
1213
from rest_framework.compat import uritemplate
1314
from rest_framework.fields import _UnvalidatedField, empty
1415

@@ -78,7 +79,9 @@ def get_schema(self, request=None, public=False):
7879

7980
class AutoSchema(ViewInspector):
8081

81-
content_types = ['application/json']
82+
request_media_types = []
83+
response_media_types = []
84+
8285
method_mapping = {
8386
'get': 'Retrieve',
8487
'post': 'Create',
@@ -336,6 +339,12 @@ def _map_field(self, field):
336339
self._map_min_max(field, content)
337340
return content
338341

342+
if isinstance(field, serializers.FileField):
343+
return {
344+
'type': 'string',
345+
'format': 'binary'
346+
}
347+
339348
# Simplest cases, default to 'string' type:
340349
FIELD_CLASS_SCHEMA_TYPE = {
341350
serializers.BooleanField: 'boolean',
@@ -430,9 +439,19 @@ def _get_pagninator(self):
430439
pagination_class = getattr(self.view, 'pagination_class', None)
431440
if pagination_class:
432441
return pagination_class()
433-
434442
return None
435443

444+
def map_parsers(self, path, method):
445+
return list(map(attrgetter('media_type'), self.view.parser_classes))
446+
447+
def map_renderers(self, path, method):
448+
media_types = []
449+
for renderer in self.view.renderer_classes:
450+
# I assume this is not relevant to OpenAPI spec
451+
if renderer != renderers.BrowsableAPIRenderer:
452+
media_types.append(renderer.media_type)
453+
return media_types
454+
436455
def _get_serializer(self, method, path):
437456
view = self.view
438457

@@ -452,6 +471,8 @@ def _get_request_body(self, path, method):
452471
if method not in ('PUT', 'PATCH', 'POST'):
453472
return {}
454473

474+
self.request_media_types = self.map_parsers(path, method)
475+
455476
serializer = self._get_serializer(path, method)
456477

457478
if not isinstance(serializer, serializers.Serializer):
@@ -469,7 +490,7 @@ def _get_request_body(self, path, method):
469490
return {
470491
'content': {
471492
ct: {'schema': content}
472-
for ct in self.content_types
493+
for ct in self.request_media_types
473494
}
474495
}
475496

@@ -482,6 +503,8 @@ def _get_responses(self, path, method):
482503
}
483504
}
484505

506+
self.response_media_types = self.map_renderers(path, method)
507+
485508
item_schema = {}
486509
serializer = self._get_serializer(path, method)
487510

@@ -509,7 +532,7 @@ def _get_responses(self, path, method):
509532
'200': {
510533
'content': {
511534
ct: {'schema': response_schema}
512-
for ct in self.content_types
535+
for ct in self.response_media_types
513536
},
514537
# description is a mandatory property,
515538
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject

tests/schemas/test_openapi.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,30 @@ class View(generics.DestroyAPIView):
339339
},
340340
}
341341

342+
def test_multipart_request_body_generation(self):
343+
"""Test that a view's delete method generates a proper response body schema."""
344+
path = '/{id}/'
345+
method = 'POST'
346+
347+
class ItemSerializer(serializers.Serializer):
348+
attachment = serializers.FileField()
349+
350+
class View(generics.CreateAPIView):
351+
serializer_class = ItemSerializer
352+
353+
view = create_view(
354+
View,
355+
method,
356+
create_request(path),
357+
)
358+
inspector = AutoSchema()
359+
inspector.view = view
360+
361+
request_body = inspector._get_request_body(path, method)
362+
assert 'multipart/form-data' in request_body['content']
363+
attachment = request_body['content']['multipart/form-data']['schema']['properties']['attachment']
364+
assert attachment['format'] == 'binary'
365+
342366
def test_retrieve_response_body_generation(self):
343367
"""
344368
Test that a list of properties is returned for retrieve item views.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy