feat: FloatField optionally validates that the number is no greater than or equals a given value.

This commit is contained in:
Anes Foufa 2020-07-28 16:52:54 +02:00
parent 599e2b183d
commit a03b356e28
4 changed files with 42 additions and 5 deletions

View File

@ -276,10 +276,11 @@ A floating point representation.
Corresponds to `django.db.models.fields.FloatField`.
**Signature**: `FloatField(max_value=None, min_value=None)`
**Signature**: `FloatField(max_value=None, min_value=None, exclusive_min=False)`
- `max_value` Validate that the number provided is no greater than this value.
- `min_value` Validate that the number provided is no less than this value.
- `exclusive_min` If true, validate that the number provided is no greater than or equals `min_value`.
## DecimalField

View File

@ -38,7 +38,7 @@ from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.settings import api_settings
from rest_framework.utils import html, humanize_datetime, json, representation
from rest_framework.utils.formatting import lazy_format
from rest_framework.validators import ProhibitSurrogateCharactersValidator
from rest_framework.validators import ExclusiveLMinValueValidator, ProhibitSurrogateCharactersValidator
class empty:
@ -968,6 +968,7 @@ class FloatField(Field):
'invalid': _('A valid number is required.'),
'max_value': _('Ensure this value is less than or equal to {max_value}.'),
'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
'exclusive_min_value': _('Ensure this value is greater than {min_value}.'),
'max_string_length': _('String value too large.')
}
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.
@ -975,15 +976,21 @@ class FloatField(Field):
def __init__(self, **kwargs):
self.max_value = kwargs.pop('max_value', None)
self.min_value = kwargs.pop('min_value', None)
self.exclusive_min = kwargs.pop("exclusive_min", False)
super().__init__(**kwargs)
if self.max_value is not None:
message = lazy_format(self.error_messages['max_value'], max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None:
message = lazy_format(self.error_messages['min_value'], min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
if self.exclusive_min:
message = lazy_format(self.error_messages["exclusive_min_value"], min_value=self.min_value)
self.validators.append(
ExclusiveLMinValueValidator(self.min_value, message=message))
else:
message = lazy_format(self.error_messages['min_value'], min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, data):

View File

@ -6,6 +6,7 @@ This gives us better separation of concerns, allows us to use single-step
object creation, and makes it possible to switch between using the implicit
`ModelSerializer` class and an equivalent explicit `Serializer` class.
"""
from django.core.validators import BaseValidator
from django.db import DataError
from django.utils.translation import gettext_lazy as _
@ -278,3 +279,11 @@ class UniqueForYearValidator(BaseUniqueForValidator):
filter_kwargs[field_name] = value
filter_kwargs['%s__year' % date_field_name] = date.year
return qs_filter(queryset, **filter_kwargs)
class ExclusiveLMinValueValidator(BaseValidator):
message = _('Ensure this value is greater than %(limit_value)s.')
code = "exclusive_min_value"
def compare(self, a, b):
return a <= b

View File

@ -1076,6 +1076,26 @@ class TestMinMaxFloatField(FieldValues):
field = serializers.FloatField(min_value=1, max_value=3)
class TestExclusiveMinFloatField(FieldValues):
"""
Valid and invalid values for 'FloatField' with exclusive_min limits.
"""
valid_inputs = {
'1.01': 1.01,
'3': 3,
1.01: 1.01,
3: 3,
3.0: 3.0,
}
invalid_inputs = {
1: ['Ensure this value is greater than 1.'],
'1': ['Ensure this value is greater than 1.'],
'1.0': ['Ensure this value is greater than 1.'],
}
outputs = {}
field = serializers.FloatField(min_value=1, exclusive_min=True)
class TestDecimalField(FieldValues):
"""
Valid and invalid values for `DecimalField`.