mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-28 00:49:49 +03:00
Merge branch 'master' into fix-7253
This commit is contained in:
commit
a8cb0f3feb
|
@ -273,7 +273,7 @@ By default this will include the following keys: `view`, `request`, `response`,
|
|||
|
||||
The following is an example plaintext renderer that will return a response with the `data` parameter as the content of the response.
|
||||
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.encoding import smart_text
|
||||
from rest_framework import renderers
|
||||
|
||||
|
||||
|
@ -282,7 +282,7 @@ The following is an example plaintext renderer that will return a response with
|
|||
format = 'txt'
|
||||
|
||||
def render(self, data, media_type=None, renderer_context=None):
|
||||
return data.encode(self.charset)
|
||||
return smart_text(data, encoding=self.charset)
|
||||
|
||||
## Setting the character set
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ each Python and Django series.
|
|||
|
||||
The following packages are optional:
|
||||
|
||||
* [coreapi][coreapi] (1.32.0+) - Schema generation support.
|
||||
* [PyYAML][pyyaml], [uritemplate][uriteemplate] (5.1+, 3.0.0+) - Schema generation support.
|
||||
* [Markdown][markdown] (3.0.0+) - Markdown support for the browsable API.
|
||||
* [Pygments][pygments] (2.4.0+) - Add syntax highlighting to Markdown processing.
|
||||
* [django-filter][django-filter] (1.0.1+) - Filtering support.
|
||||
|
@ -237,7 +237,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
[redhat]: https://www.redhat.com/
|
||||
[heroku]: https://www.heroku.com/
|
||||
[eventbrite]: https://www.eventbrite.co.uk/about/
|
||||
[coreapi]: https://pypi.org/project/coreapi/
|
||||
[pyyaml]: https://pypi.org/project/PyYAML/
|
||||
[uriteemplate]: https://pypi.org/project/uritemplate/
|
||||
[markdown]: https://pypi.org/project/Markdown/
|
||||
[pygments]: https://pypi.org/project/Pygments/
|
||||
[django-filter]: https://pypi.org/project/django-filter/
|
||||
|
|
|
@ -25,9 +25,9 @@ ISO_8601 = 'iso-8601'
|
|||
default_app_config = 'rest_framework.apps.RestFrameworkConfig'
|
||||
|
||||
|
||||
class RemovedInDRF312Warning(DeprecationWarning):
|
||||
class RemovedInDRF313Warning(DeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInDRF313Warning(PendingDeprecationWarning):
|
||||
class RemovedInDRF314Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
|
|
@ -8,7 +8,6 @@ from functools import reduce
|
|||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db import models
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.db.models.sql.constants import ORDER_PATTERN
|
||||
from django.template import loader
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -256,7 +255,13 @@ class OrderingFilter(BaseFilterBackend):
|
|||
|
||||
def remove_invalid_fields(self, queryset, fields, view, request):
|
||||
valid_fields = [item[0] for item in self.get_valid_fields(queryset, view, {'request': request})]
|
||||
return [term for term in fields if term.lstrip('-') in valid_fields and ORDER_PATTERN.match(term)]
|
||||
|
||||
def term_valid(term):
|
||||
if term.startswith("-"):
|
||||
term = term[1:]
|
||||
return term in valid_fields
|
||||
|
||||
return [term for term in fields if term_valid(term)]
|
||||
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
ordering = self.get_ordering(request, queryset, view)
|
||||
|
|
|
@ -12,7 +12,9 @@ from django.core.validators import (
|
|||
from django.db import models
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from rest_framework import exceptions, renderers, serializers
|
||||
from rest_framework import (
|
||||
RemovedInDRF314Warning, exceptions, renderers, serializers
|
||||
)
|
||||
from rest_framework.compat import uritemplate
|
||||
from rest_framework.fields import _UnvalidatedField, empty
|
||||
from rest_framework.settings import api_settings
|
||||
|
@ -146,15 +148,15 @@ class AutoSchema(ViewInspector):
|
|||
operation['description'] = self.get_description(path, method)
|
||||
|
||||
parameters = []
|
||||
parameters += self._get_path_parameters(path, method)
|
||||
parameters += self._get_pagination_parameters(path, method)
|
||||
parameters += self._get_filter_parameters(path, method)
|
||||
parameters += self.get_path_parameters(path, method)
|
||||
parameters += self.get_pagination_parameters(path, method)
|
||||
parameters += self.get_filter_parameters(path, method)
|
||||
operation['parameters'] = parameters
|
||||
|
||||
request_body = self._get_request_body(path, method)
|
||||
request_body = self.get_request_body(path, method)
|
||||
if request_body:
|
||||
operation['requestBody'] = request_body
|
||||
operation['responses'] = self._get_responses(path, method)
|
||||
operation['responses'] = self.get_responses(path, method)
|
||||
operation['tags'] = self.get_tags(path, method)
|
||||
|
||||
return operation
|
||||
|
@ -186,14 +188,18 @@ class AutoSchema(ViewInspector):
|
|||
"""
|
||||
Return components with their properties from the serializer.
|
||||
"""
|
||||
serializer = self._get_serializer(path, method)
|
||||
|
||||
if method.lower() == 'delete':
|
||||
return {}
|
||||
|
||||
serializer = self.get_serializer(path, method)
|
||||
|
||||
if not isinstance(serializer, serializers.Serializer):
|
||||
return {}
|
||||
|
||||
component_name = self.get_component_name(serializer)
|
||||
|
||||
content = self._map_serializer(serializer)
|
||||
content = self.map_serializer(serializer)
|
||||
return {component_name: content}
|
||||
|
||||
def _to_camel_case(self, snake_str):
|
||||
|
@ -216,8 +222,8 @@ class AutoSchema(ViewInspector):
|
|||
name = model.__name__
|
||||
|
||||
# Try with the serializer class name
|
||||
elif self._get_serializer(path, method) is not None:
|
||||
name = self._get_serializer(path, method).__class__.__name__
|
||||
elif self.get_serializer(path, method) is not None:
|
||||
name = self.get_serializer(path, method).__class__.__name__
|
||||
if name.endswith('Serializer'):
|
||||
name = name[:-10]
|
||||
|
||||
|
@ -255,7 +261,7 @@ class AutoSchema(ViewInspector):
|
|||
|
||||
return action + name
|
||||
|
||||
def _get_path_parameters(self, path, method):
|
||||
def get_path_parameters(self, path, method):
|
||||
"""
|
||||
Return a list of parameters from templated path variables.
|
||||
"""
|
||||
|
@ -291,15 +297,15 @@ class AutoSchema(ViewInspector):
|
|||
|
||||
return parameters
|
||||
|
||||
def _get_filter_parameters(self, path, method):
|
||||
if not self._allows_filters(path, method):
|
||||
def get_filter_parameters(self, path, method):
|
||||
if not self.allows_filters(path, method):
|
||||
return []
|
||||
parameters = []
|
||||
for filter_backend in self.view.filter_backends:
|
||||
parameters += filter_backend().get_schema_operation_parameters(self.view)
|
||||
return parameters
|
||||
|
||||
def _allows_filters(self, path, method):
|
||||
def allows_filters(self, path, method):
|
||||
"""
|
||||
Determine whether to include filter Fields in schema.
|
||||
|
||||
|
@ -312,19 +318,19 @@ class AutoSchema(ViewInspector):
|
|||
return self.view.action in ["list", "retrieve", "update", "partial_update", "destroy"]
|
||||
return method.lower() in ["get", "put", "patch", "delete"]
|
||||
|
||||
def _get_pagination_parameters(self, path, method):
|
||||
def get_pagination_parameters(self, path, method):
|
||||
view = self.view
|
||||
|
||||
if not is_list_view(path, method, view):
|
||||
return []
|
||||
|
||||
paginator = self._get_paginator()
|
||||
paginator = self.get_paginator()
|
||||
if not paginator:
|
||||
return []
|
||||
|
||||
return paginator.get_schema_operation_parameters(view)
|
||||
|
||||
def _map_choicefield(self, field):
|
||||
def map_choicefield(self, field):
|
||||
choices = list(OrderedDict.fromkeys(field.choices)) # preserve order and remove duplicates
|
||||
mapping = {
|
||||
# The value of `enum` keyword MUST be an array and SHOULD be unique.
|
||||
|
@ -351,16 +357,16 @@ class AutoSchema(ViewInspector):
|
|||
|
||||
return mapping
|
||||
|
||||
def _map_field(self, field):
|
||||
def map_field(self, field):
|
||||
|
||||
# Nested Serializers, `many` or not.
|
||||
if isinstance(field, serializers.ListSerializer):
|
||||
return {
|
||||
'type': 'array',
|
||||
'items': self._map_serializer(field.child)
|
||||
'items': self.map_serializer(field.child)
|
||||
}
|
||||
if isinstance(field, serializers.Serializer):
|
||||
data = self._map_serializer(field)
|
||||
data = self.map_serializer(field)
|
||||
data['type'] = 'object'
|
||||
return data
|
||||
|
||||
|
@ -368,7 +374,7 @@ class AutoSchema(ViewInspector):
|
|||
if isinstance(field, serializers.ManyRelatedField):
|
||||
return {
|
||||
'type': 'array',
|
||||
'items': self._map_field(field.child_relation)
|
||||
'items': self.map_field(field.child_relation)
|
||||
}
|
||||
if isinstance(field, serializers.PrimaryKeyRelatedField):
|
||||
model = getattr(field.queryset, 'model', None)
|
||||
|
@ -384,11 +390,11 @@ class AutoSchema(ViewInspector):
|
|||
if isinstance(field, serializers.MultipleChoiceField):
|
||||
return {
|
||||
'type': 'array',
|
||||
'items': self._map_choicefield(field)
|
||||
'items': self.map_choicefield(field)
|
||||
}
|
||||
|
||||
if isinstance(field, serializers.ChoiceField):
|
||||
return self._map_choicefield(field)
|
||||
return self.map_choicefield(field)
|
||||
|
||||
# ListField.
|
||||
if isinstance(field, serializers.ListField):
|
||||
|
@ -397,7 +403,7 @@ class AutoSchema(ViewInspector):
|
|||
'items': {},
|
||||
}
|
||||
if not isinstance(field.child, _UnvalidatedField):
|
||||
mapping['items'] = self._map_field(field.child)
|
||||
mapping['items'] = self.map_field(field.child)
|
||||
return mapping
|
||||
|
||||
# DateField and DateTimeField type is string
|
||||
|
@ -442,11 +448,17 @@ class AutoSchema(ViewInspector):
|
|||
content['format'] = field.protocol
|
||||
return content
|
||||
|
||||
# DecimalField has multipleOf based on decimal_places
|
||||
if isinstance(field, serializers.DecimalField):
|
||||
content = {
|
||||
'type': 'number'
|
||||
}
|
||||
if getattr(field, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING):
|
||||
content = {
|
||||
'type': 'string',
|
||||
'format': 'decimal',
|
||||
}
|
||||
else:
|
||||
content = {
|
||||
'type': 'number'
|
||||
}
|
||||
|
||||
if field.decimal_places:
|
||||
content['multipleOf'] = float('.' + (field.decimal_places - 1) * '0' + '1')
|
||||
if field.max_whole_digits:
|
||||
|
@ -457,7 +469,7 @@ class AutoSchema(ViewInspector):
|
|||
|
||||
if isinstance(field, serializers.FloatField):
|
||||
content = {
|
||||
'type': 'number'
|
||||
'type': 'number',
|
||||
}
|
||||
self._map_min_max(field, content)
|
||||
return content
|
||||
|
@ -493,7 +505,7 @@ class AutoSchema(ViewInspector):
|
|||
if field.min_value:
|
||||
content['minimum'] = field.min_value
|
||||
|
||||
def _map_serializer(self, serializer):
|
||||
def map_serializer(self, serializer):
|
||||
# Assuming we have a valid serializer instance.
|
||||
required = []
|
||||
properties = {}
|
||||
|
@ -505,7 +517,7 @@ class AutoSchema(ViewInspector):
|
|||
if field.required:
|
||||
required.append(field.field_name)
|
||||
|
||||
schema = self._map_field(field)
|
||||
schema = self.map_field(field)
|
||||
if field.read_only:
|
||||
schema['readOnly'] = True
|
||||
if field.write_only:
|
||||
|
@ -516,7 +528,7 @@ class AutoSchema(ViewInspector):
|
|||
schema['default'] = field.default
|
||||
if field.help_text:
|
||||
schema['description'] = str(field.help_text)
|
||||
self._map_field_validators(field, schema)
|
||||
self.map_field_validators(field, schema)
|
||||
|
||||
properties[field.field_name] = schema
|
||||
|
||||
|
@ -529,7 +541,7 @@ class AutoSchema(ViewInspector):
|
|||
|
||||
return result
|
||||
|
||||
def _map_field_validators(self, field, schema):
|
||||
def map_field_validators(self, field, schema):
|
||||
"""
|
||||
map field validators
|
||||
"""
|
||||
|
@ -556,7 +568,8 @@ class AutoSchema(ViewInspector):
|
|||
schema['maximum'] = v.limit_value
|
||||
elif isinstance(v, MinValueValidator):
|
||||
schema['minimum'] = v.limit_value
|
||||
elif isinstance(v, DecimalValidator):
|
||||
elif isinstance(v, DecimalValidator) and \
|
||||
not getattr(field, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING):
|
||||
if v.decimal_places:
|
||||
schema['multipleOf'] = float('.' + (v.decimal_places - 1) * '0' + '1')
|
||||
if v.max_digits:
|
||||
|
@ -566,7 +579,7 @@ class AutoSchema(ViewInspector):
|
|||
schema['maximum'] = int(digits * '9') + 1
|
||||
schema['minimum'] = -schema['maximum']
|
||||
|
||||
def _get_paginator(self):
|
||||
def get_paginator(self):
|
||||
pagination_class = getattr(self.view, 'pagination_class', None)
|
||||
if pagination_class:
|
||||
return pagination_class()
|
||||
|
@ -584,7 +597,7 @@ class AutoSchema(ViewInspector):
|
|||
media_types.append(renderer.media_type)
|
||||
return media_types
|
||||
|
||||
def _get_serializer(self, path, method):
|
||||
def get_serializer(self, path, method):
|
||||
view = self.view
|
||||
|
||||
if not hasattr(view, 'get_serializer'):
|
||||
|
@ -602,13 +615,13 @@ class AutoSchema(ViewInspector):
|
|||
def _get_reference(self, serializer):
|
||||
return {'$ref': '#/components/schemas/{}'.format(self.get_component_name(serializer))}
|
||||
|
||||
def _get_request_body(self, path, method):
|
||||
def get_request_body(self, path, method):
|
||||
if method not in ('PUT', 'PATCH', 'POST'):
|
||||
return {}
|
||||
|
||||
self.request_media_types = self.map_parsers(path, method)
|
||||
|
||||
serializer = self._get_serializer(path, method)
|
||||
serializer = self.get_serializer(path, method)
|
||||
|
||||
if not isinstance(serializer, serializers.Serializer):
|
||||
item_schema = {}
|
||||
|
@ -622,8 +635,7 @@ class AutoSchema(ViewInspector):
|
|||
}
|
||||
}
|
||||
|
||||
def _get_responses(self, path, method):
|
||||
# TODO: Handle multiple codes and pagination classes.
|
||||
def get_responses(self, path, method):
|
||||
if method == 'DELETE':
|
||||
return {
|
||||
'204': {
|
||||
|
@ -633,7 +645,7 @@ class AutoSchema(ViewInspector):
|
|||
|
||||
self.response_media_types = self.map_renderers(path, method)
|
||||
|
||||
serializer = self._get_serializer(path, method)
|
||||
serializer = self.get_serializer(path, method)
|
||||
|
||||
if not isinstance(serializer, serializers.Serializer):
|
||||
item_schema = {}
|
||||
|
@ -645,7 +657,7 @@ class AutoSchema(ViewInspector):
|
|||
'type': 'array',
|
||||
'items': item_schema,
|
||||
}
|
||||
paginator = self._get_paginator()
|
||||
paginator = self.get_paginator()
|
||||
if paginator:
|
||||
response_schema = paginator.get_paginated_response_schema(response_schema)
|
||||
else:
|
||||
|
@ -676,3 +688,99 @@ class AutoSchema(ViewInspector):
|
|||
path = path[1:]
|
||||
|
||||
return [path.split('/')[0].replace('_', '-')]
|
||||
|
||||
def _get_path_parameters(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_get_path_parameters()` has been renamed to `get_path_parameters()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_path_parameters(path, method)
|
||||
|
||||
def _get_filter_parameters(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_get_filter_parameters()` has been renamed to `get_filter_parameters()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_filter_parameters(path, method)
|
||||
|
||||
def _get_responses(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_get_responses()` has been renamed to `get_responses()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_responses(path, method)
|
||||
|
||||
def _get_request_body(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_get_request_body()` has been renamed to `get_request_body()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_request_body(path, method)
|
||||
|
||||
def _get_serializer(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_get_serializer()` has been renamed to `get_serializer()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_serializer(path, method)
|
||||
|
||||
def _get_paginator(self):
|
||||
warnings.warn(
|
||||
"Method `_get_paginator()` has been renamed to `get_paginator()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_paginator()
|
||||
|
||||
def _map_field_validators(self, field, schema):
|
||||
warnings.warn(
|
||||
"Method `_map_field_validators()` has been renamed to `map_field_validators()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.map_field_validators(field, schema)
|
||||
|
||||
def _map_serializer(self, serializer):
|
||||
warnings.warn(
|
||||
"Method `_map_serializer()` has been renamed to `map_serializer()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.map_serializer(serializer)
|
||||
|
||||
def _map_field(self, field):
|
||||
warnings.warn(
|
||||
"Method `_map_field()` has been renamed to `map_field()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.map_field(field)
|
||||
|
||||
def _map_choicefield(self, field):
|
||||
warnings.warn(
|
||||
"Method `_map_choicefield()` has been renamed to `map_choicefield()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.map_choicefield(field)
|
||||
|
||||
def _get_pagination_parameters(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_get_pagination_parameters()` has been renamed to `get_pagination_parameters()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.get_pagination_parameters(path, method)
|
||||
|
||||
def _allows_filters(self, path, method):
|
||||
warnings.warn(
|
||||
"Method `_allows_filters()` has been renamed to `allows_filters()`. "
|
||||
"The old name will be removed in DRF v3.14.",
|
||||
RemovedInDRF314Warning, stacklevel=2
|
||||
)
|
||||
return self.allows_filters(path, method)
|
||||
|
|
|
@ -87,7 +87,7 @@ class TestFieldMapping(TestCase):
|
|||
]
|
||||
for field, mapping in cases:
|
||||
with self.subTest(field=field):
|
||||
assert inspector._map_field(field) == mapping
|
||||
assert inspector.map_field(field) == mapping
|
||||
|
||||
@override_settings(REST_FRAMEWORK={'COERCE_DECIMAL_TO_STRING': False})
|
||||
def test_decimal_schema_for_choice_field(self):
|
||||
|
@ -104,7 +104,7 @@ class TestFieldMapping(TestCase):
|
|||
|
||||
inspector = AutoSchema()
|
||||
|
||||
data = inspector._map_serializer(ItemSerializer())
|
||||
data = inspector.map_serializer(ItemSerializer())
|
||||
assert isinstance(data['properties']['text']['description'], str), "description must be str"
|
||||
|
||||
def test_boolean_default_field(self):
|
||||
|
@ -115,7 +115,7 @@ class TestFieldMapping(TestCase):
|
|||
|
||||
inspector = AutoSchema()
|
||||
|
||||
data = inspector._map_serializer(Serializer())
|
||||
data = inspector.map_serializer(Serializer())
|
||||
assert data['properties']['default_true']['default'] is True, "default must be true"
|
||||
assert data['properties']['default_false']['default'] is False, "default must be false"
|
||||
assert 'default' not in data['properties']['without_default'], "default must not be defined"
|
||||
|
@ -215,7 +215,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
request_body = inspector._get_request_body(path, method)
|
||||
request_body = inspector.get_request_body(path, method)
|
||||
print(request_body)
|
||||
assert request_body['content']['application/json']['schema']['$ref'] == '#/components/schemas/Item'
|
||||
|
||||
|
@ -242,7 +242,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
serializer = inspector._get_serializer(path, method)
|
||||
serializer = inspector.get_serializer(path, method)
|
||||
|
||||
with pytest.raises(Exception) as exc:
|
||||
inspector.get_component_name(serializer)
|
||||
|
@ -272,7 +272,7 @@ class TestOperationIntrospection(TestCase):
|
|||
# there should be no empty 'required' property, see #6834
|
||||
assert 'required' not in component
|
||||
|
||||
for response in inspector._get_responses(path, method).values():
|
||||
for response in inspector.get_responses(path, method).values():
|
||||
assert 'required' not in component
|
||||
|
||||
def test_empty_required_with_patch_method(self):
|
||||
|
@ -298,7 +298,7 @@ class TestOperationIntrospection(TestCase):
|
|||
component = components['Item']
|
||||
# there should be no empty 'required' property, see #6834
|
||||
assert 'required' not in component
|
||||
for response in inspector._get_responses(path, method).values():
|
||||
for response in inspector.get_responses(path, method).values():
|
||||
assert 'required' not in component
|
||||
|
||||
def test_response_body_generation(self):
|
||||
|
@ -320,7 +320,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
assert responses['201']['content']['application/json']['schema']['$ref'] == '#/components/schemas/Item'
|
||||
|
||||
components = inspector.get_components(path, method)
|
||||
|
@ -350,7 +350,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
assert responses['201']['content']['application/json']['schema']['$ref'] == '#/components/schemas/Item'
|
||||
components = inspector.get_components(path, method)
|
||||
assert components['Item']
|
||||
|
@ -381,7 +381,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
assert responses == {
|
||||
'200': {
|
||||
'description': '',
|
||||
|
@ -437,7 +437,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
assert responses == {
|
||||
'200': {
|
||||
'description': '',
|
||||
|
@ -485,7 +485,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
assert responses == {
|
||||
'204': {
|
||||
'description': '',
|
||||
|
@ -509,7 +509,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
request_body = inspector._get_request_body(path, method)
|
||||
request_body = inspector.get_request_body(path, method)
|
||||
|
||||
assert len(request_body['content'].keys()) == 2
|
||||
assert 'multipart/form-data' in request_body['content']
|
||||
|
@ -532,7 +532,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
# TODO this should be changed once the multiple response
|
||||
# schema support is there
|
||||
success_response = responses['200']
|
||||
|
@ -607,7 +607,7 @@ class TestOperationIntrospection(TestCase):
|
|||
inspector = AutoSchema()
|
||||
inspector.view = view
|
||||
|
||||
responses = inspector._get_responses(path, method)
|
||||
responses = inspector.get_responses(path, method)
|
||||
assert responses == {
|
||||
'200': {
|
||||
'description': '',
|
||||
|
@ -851,6 +851,16 @@ class TestOperationIntrospection(TestCase):
|
|||
assert properties['decimal2']['type'] == 'number'
|
||||
assert properties['decimal2']['multipleOf'] == .0001
|
||||
|
||||
assert properties['decimal3'] == {
|
||||
'type': 'string', 'format': 'decimal', 'maximum': 1000000, 'minimum': -1000000, 'multipleOf': 0.01
|
||||
}
|
||||
assert properties['decimal4'] == {
|
||||
'type': 'string', 'format': 'decimal', 'maximum': 1000000, 'minimum': -1000000, 'multipleOf': 0.01
|
||||
}
|
||||
assert properties['decimal5'] == {
|
||||
'type': 'string', 'format': 'decimal', 'maximum': 10000, 'minimum': -10000, 'multipleOf': 0.01
|
||||
}
|
||||
|
||||
assert properties['email']['type'] == 'string'
|
||||
assert properties['email']['format'] == 'email'
|
||||
assert properties['email']['default'] == 'foo@bar.com'
|
||||
|
@ -1100,3 +1110,15 @@ class TestGenerator(TestCase):
|
|||
assert 'components' in schema
|
||||
assert 'schemas' in schema['components']
|
||||
assert 'Duplicate' in schema['components']['schemas']
|
||||
|
||||
def test_component_should_not_be_generated_for_delete_method(self):
|
||||
class ExampleView(generics.DestroyAPIView):
|
||||
schema = AutoSchema(operation_id_base='example')
|
||||
|
||||
url_patterns = [
|
||||
url(r'^example/?$', ExampleView.as_view()),
|
||||
]
|
||||
generator = SchemaGenerator(patterns=url_patterns)
|
||||
schema = generator.get_schema(request=create_request('/'))
|
||||
assert 'components' not in schema
|
||||
assert 'content' not in schema['paths']['/example/']['delete']['responses']['204']
|
||||
|
|
|
@ -119,9 +119,13 @@ class ExampleValidatedSerializer(serializers.Serializer):
|
|||
MinLengthValidator(limit_value=2),
|
||||
)
|
||||
)
|
||||
decimal1 = serializers.DecimalField(max_digits=6, decimal_places=2)
|
||||
decimal2 = serializers.DecimalField(max_digits=5, decimal_places=0,
|
||||
decimal1 = serializers.DecimalField(max_digits=6, decimal_places=2, coerce_to_string=False)
|
||||
decimal2 = serializers.DecimalField(max_digits=5, decimal_places=0, coerce_to_string=False,
|
||||
validators=(DecimalValidator(max_digits=17, decimal_places=4),))
|
||||
decimal3 = serializers.DecimalField(max_digits=8, decimal_places=2, coerce_to_string=True)
|
||||
decimal4 = serializers.DecimalField(max_digits=8, decimal_places=2, coerce_to_string=True,
|
||||
validators=(DecimalValidator(max_digits=17, decimal_places=4),))
|
||||
decimal5 = serializers.DecimalField(max_digits=6, decimal_places=2)
|
||||
email = serializers.EmailField(default='foo@bar.com')
|
||||
url = serializers.URLField(default='http://www.example.com', allow_null=True)
|
||||
uuid = serializers.UUIDField()
|
||||
|
|
Loading…
Reference in New Issue
Block a user