mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-28 08:59:54 +03:00
Corrected OpenAPI schema type for DecimalField
The API renders DecimalFields as strings. The generated schema now renders decimal fields correctly as strings. Fixes #7253
This commit is contained in:
parent
734c534dbb
commit
e21156ff17
|
@ -6,8 +6,8 @@ from operator import attrgetter
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.core.validators import (
|
from django.core.validators import (
|
||||||
DecimalValidator, EmailValidator, MaxLengthValidator, MaxValueValidator,
|
EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator,
|
||||||
MinLengthValidator, MinValueValidator, RegexValidator, URLValidator
|
MinValueValidator, RegexValidator, URLValidator
|
||||||
)
|
)
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
|
@ -329,10 +329,10 @@ class AutoSchema(ViewInspector):
|
||||||
type = 'boolean'
|
type = 'boolean'
|
||||||
elif all(isinstance(choice, int) for choice in choices):
|
elif all(isinstance(choice, int) for choice in choices):
|
||||||
type = 'integer'
|
type = 'integer'
|
||||||
elif all(isinstance(choice, (int, float, Decimal)) for choice in choices): # `number` includes `integer`
|
elif all(isinstance(choice, (int, float)) for choice in choices): # `number` includes `integer`
|
||||||
# Ref: https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.21
|
# Ref: https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.21
|
||||||
type = 'number'
|
type = 'number'
|
||||||
elif all(isinstance(choice, str) for choice in choices):
|
elif all(isinstance(choice, (str, Decimal)) for choice in choices):
|
||||||
type = 'string'
|
type = 'string'
|
||||||
else:
|
else:
|
||||||
type = None
|
type = None
|
||||||
|
@ -442,18 +442,11 @@ class AutoSchema(ViewInspector):
|
||||||
content['format'] = field.protocol
|
content['format'] = field.protocol
|
||||||
return content
|
return content
|
||||||
|
|
||||||
# DecimalField has multipleOf based on decimal_places
|
|
||||||
if isinstance(field, serializers.DecimalField):
|
if isinstance(field, serializers.DecimalField):
|
||||||
content = {
|
return {
|
||||||
'type': 'number'
|
'type': 'string',
|
||||||
|
'format': 'decimal'
|
||||||
}
|
}
|
||||||
if field.decimal_places:
|
|
||||||
content['multipleOf'] = float('.' + (field.decimal_places - 1) * '0' + '1')
|
|
||||||
if field.max_whole_digits:
|
|
||||||
content['maximum'] = int(field.max_whole_digits * '9') + 1
|
|
||||||
content['minimum'] = -content['maximum']
|
|
||||||
self._map_min_max(field, content)
|
|
||||||
return content
|
|
||||||
|
|
||||||
if isinstance(field, serializers.FloatField):
|
if isinstance(field, serializers.FloatField):
|
||||||
content = {
|
content = {
|
||||||
|
@ -556,15 +549,6 @@ class AutoSchema(ViewInspector):
|
||||||
schema['maximum'] = v.limit_value
|
schema['maximum'] = v.limit_value
|
||||||
elif isinstance(v, MinValueValidator):
|
elif isinstance(v, MinValueValidator):
|
||||||
schema['minimum'] = v.limit_value
|
schema['minimum'] = v.limit_value
|
||||||
elif isinstance(v, DecimalValidator):
|
|
||||||
if v.decimal_places:
|
|
||||||
schema['multipleOf'] = float('.' + (v.decimal_places - 1) * '0' + '1')
|
|
||||||
if v.max_digits:
|
|
||||||
digits = v.max_digits
|
|
||||||
if v.decimal_places is not None and v.decimal_places > 0:
|
|
||||||
digits -= v.decimal_places
|
|
||||||
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)
|
pagination_class = getattr(self.view, 'pagination_class', None)
|
||||||
|
|
|
@ -830,13 +830,9 @@ class TestOperationIntrospection(TestCase):
|
||||||
assert properties['regex']['pattern'] == r'[ABC]12{3}'
|
assert properties['regex']['pattern'] == r'[ABC]12{3}'
|
||||||
assert properties['regex']['description'] == 'must have an A, B, or C followed by 1222'
|
assert properties['regex']['description'] == 'must have an A, B, or C followed by 1222'
|
||||||
|
|
||||||
assert properties['decimal1']['type'] == 'number'
|
assert properties['decimal1'] == {'type': 'string', 'format': 'decimal'}
|
||||||
assert properties['decimal1']['multipleOf'] == .01
|
|
||||||
assert properties['decimal1']['maximum'] == 10000
|
|
||||||
assert properties['decimal1']['minimum'] == -10000
|
|
||||||
|
|
||||||
assert properties['decimal2']['type'] == 'number'
|
assert properties['decimal2'] == {'type': 'string', 'format': 'decimal'}
|
||||||
assert properties['decimal2']['multipleOf'] == .0001
|
|
||||||
|
|
||||||
assert properties['email']['type'] == 'string'
|
assert properties['email']['type'] == 'string'
|
||||||
assert properties['email']['format'] == 'email'
|
assert properties['email']['format'] == 'email'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user