first version of fix only for min and max value

This commit is contained in:
Vignesh 2017-09-11 20:00:48 +08:00 committed by Carlton Gibson
parent 0f33e63e10
commit 56daa693df
4 changed files with 50 additions and 13 deletions

View File

@ -987,8 +987,8 @@ class FloatField(Field):
class DecimalField(Field): class DecimalField(Field):
default_error_messages = { default_error_messages = {
'invalid': _('A valid number is required.'), 'invalid': _('A valid number is required.'),
'max_value': _('Ensure this value is less than or equal to {max_value}.'), 'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
'min_value': _('Ensure this value is greater than or equal to {min_value}.'), 'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'),
'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'), 'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'),
'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'), 'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'),
'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), 'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'),

View File

@ -127,12 +127,13 @@ def get_field_kwargs(field_name, model_field):
else: else:
# Ensure that max_value is passed explicitly as a keyword arg, # Ensure that max_value is passed explicitly as a keyword arg,
# rather than as a validator. # rather than as a validator.
max_value = next(( max_value, messsage = next((
validator.limit_value for validator in validator_kwarg (validator.limit_value, validator.message) for validator in validator_kwarg
if isinstance(validator, validators.MaxValueValidator) if isinstance(validator, validators.MaxValueValidator)
), None) ), (None, None))
if max_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES): if max_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES):
kwargs['max_value'] = max_value kwargs['max_value'] = max_value
kwargs['error_messages'] = {'max_value': messsage}
validator_kwarg = [ validator_kwarg = [
validator for validator in validator_kwarg validator for validator in validator_kwarg
if not isinstance(validator, validators.MaxValueValidator) if not isinstance(validator, validators.MaxValueValidator)
@ -140,12 +141,13 @@ def get_field_kwargs(field_name, model_field):
# Ensure that min_value is passed explicitly as a keyword arg, # Ensure that min_value is passed explicitly as a keyword arg,
# rather than as a validator. # rather than as a validator.
min_value = next(( min_value, messsage = next((
validator.limit_value for validator in validator_kwarg (validator.limit_value, validator.message) for validator in validator_kwarg
if isinstance(validator, validators.MinValueValidator) if isinstance(validator, validators.MinValueValidator)
), None) ), (None, None))
if min_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES): if min_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES):
kwargs['min_value'] = min_value kwargs['min_value'] = min_value
kwargs['error_messages'] = {**kwargs['error_messages'], **{'min_value': messsage}}
validator_kwarg = [ validator_kwarg = [
validator for validator in validator_kwarg validator for validator in validator_kwarg
if not isinstance(validator, validators.MinValueValidator) if not isinstance(validator, validators.MinValueValidator)

View File

@ -200,7 +200,7 @@ class TestRegularFieldMappings(TestCase):
expected = dedent(""" expected = dedent("""
TestSerializer(): TestSerializer():
id = IntegerField(label='ID', read_only=True) id = IntegerField(label='ID', read_only=True)
value_limit_field = IntegerField(max_value=10, min_value=1) value_limit_field = IntegerField(error_messages={'max_value': 'Ensure this value is less than or equal to %(limit_value)s.', 'min_value': 'Ensure this value is greater than or equal to %(limit_value)s.'}, max_value=10, min_value=1)
length_limit_field = CharField(max_length=12, min_length=3) length_limit_field = CharField(max_length=12, min_length=3)
blank_field = CharField(allow_blank=True, max_length=10, required=False) blank_field = CharField(allow_blank=True, max_length=10, required=False)
null_field = IntegerField(allow_null=True, required=False) null_field = IntegerField(allow_null=True, required=False)

View File

@ -1,6 +1,7 @@
import datetime import datetime
import pytest import pytest
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import DataError, models from django.db import DataError, models
from django.test import TestCase from django.test import TestCase
@ -36,7 +37,7 @@ class RelatedModel(models.Model):
class RelatedModelSerializer(serializers.ModelSerializer): class RelatedModelSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username', username = serializers.CharField(source='user.username',
validators=[UniqueValidator(queryset=UniquenessModel.objects.all(), lookup='iexact')]) # NOQA validators=[UniqueValidator(queryset=UniquenessModel.objects.all(), lookup='iexact')]) # NOQA
class Meta: class Meta:
model = RelatedModel model = RelatedModel
@ -245,10 +246,12 @@ class TestUniquenessTogetherValidation(TestCase):
When model fields are not included in a serializer, then uniqueness When model fields are not included in a serializer, then uniqueness
validators should not be added for that field. validators should not be added for that field.
""" """
class ExcludedFieldSerializer(serializers.ModelSerializer): class ExcludedFieldSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = UniquenessTogetherModel model = UniquenessTogetherModel
fields = ('id', 'race_name',) fields = ('id', 'race_name',)
serializer = ExcludedFieldSerializer() serializer = ExcludedFieldSerializer()
expected = dedent(""" expected = dedent("""
ExcludedFieldSerializer(): ExcludedFieldSerializer():
@ -262,6 +265,7 @@ class TestUniquenessTogetherValidation(TestCase):
When serializer fields are read only, then uniqueness When serializer fields are read only, then uniqueness
validators should not be added for that field. validators should not be added for that field.
""" """
class ReadOnlyFieldSerializer(serializers.ModelSerializer): class ReadOnlyFieldSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = UniquenessTogetherModel model = UniquenessTogetherModel
@ -281,6 +285,7 @@ class TestUniquenessTogetherValidation(TestCase):
""" """
Ensure validators can be explicitly removed.. Ensure validators can be explicitly removed..
""" """
class NoValidatorsSerializer(serializers.ModelSerializer): class NoValidatorsSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = UniquenessTogetherModel model = UniquenessTogetherModel
@ -329,6 +334,7 @@ class TestUniquenessTogetherValidation(TestCase):
filter_queryset should add value from existing instance attribute filter_queryset should add value from existing instance attribute
if it is not provided in attributes dict if it is not provided in attributes dict
""" """
class MockQueryset(object): class MockQueryset(object):
def filter(self, **kwargs): def filter(self, **kwargs):
self.called_with = kwargs self.called_with = kwargs
@ -411,6 +417,7 @@ class TestUniquenessForDateValidation(TestCase):
'published': datetime.date(2000, 1, 1) 'published': datetime.date(2000, 1, 1)
} }
# Tests for `UniqueForMonthValidator` # Tests for `UniqueForMonthValidator`
# ---------------------------------- # ----------------------------------
@ -427,7 +434,6 @@ class UniqueForMonthSerializer(serializers.ModelSerializer):
class UniqueForMonthTests(TestCase): class UniqueForMonthTests(TestCase):
def setUp(self): def setUp(self):
self.instance = UniqueForMonthModel.objects.create( self.instance = UniqueForMonthModel.objects.create(
slug='existing', published='2017-01-01' slug='existing', published='2017-01-01'
@ -450,6 +456,7 @@ class UniqueForMonthTests(TestCase):
'published': datetime.date(2017, 2, 1) 'published': datetime.date(2017, 2, 1)
} }
# Tests for `UniqueForYearValidator` # Tests for `UniqueForYearValidator`
# ---------------------------------- # ----------------------------------
@ -466,7 +473,6 @@ class UniqueForYearSerializer(serializers.ModelSerializer):
class UniqueForYearTests(TestCase): class UniqueForYearTests(TestCase):
def setUp(self): def setUp(self):
self.instance = UniqueForYearModel.objects.create( self.instance = UniqueForYearModel.objects.create(
slug='existing', published='2017-01-01' slug='existing', published='2017-01-01'
@ -532,23 +538,25 @@ class TestHiddenFieldUniquenessForDateValidation(TestCase):
class ValidatorsTests(TestCase): class ValidatorsTests(TestCase):
def test_qs_exists_handles_type_error(self): def test_qs_exists_handles_type_error(self):
class TypeErrorQueryset(object): class TypeErrorQueryset(object):
def exists(self): def exists(self):
raise TypeError raise TypeError
assert qs_exists(TypeErrorQueryset()) is False assert qs_exists(TypeErrorQueryset()) is False
def test_qs_exists_handles_value_error(self): def test_qs_exists_handles_value_error(self):
class ValueErrorQueryset(object): class ValueErrorQueryset(object):
def exists(self): def exists(self):
raise ValueError raise ValueError
assert qs_exists(ValueErrorQueryset()) is False assert qs_exists(ValueErrorQueryset()) is False
def test_qs_exists_handles_data_error(self): def test_qs_exists_handles_data_error(self):
class DataErrorQueryset(object): class DataErrorQueryset(object):
def exists(self): def exists(self):
raise DataError raise DataError
assert qs_exists(DataErrorQueryset()) is False assert qs_exists(DataErrorQueryset()) is False
def test_validator_raises_error_if_not_all_fields_are_provided(self): def test_validator_raises_error_if_not_all_fields_are_provided(self):
@ -563,3 +571,30 @@ class ValidatorsTests(TestCase):
date_field='bar') date_field='bar')
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
validator.filter_queryset(attrs=None, queryset=None) validator.filter_queryset(attrs=None, queryset=None)
class ItemModel(models.Model):
price = models.DecimalField(decimal_places=2, max_digits=10, validators=[MinValueValidator(limit_value=0, message='Price has to be >= 0.'),
MaxValueValidator(limit_value=10, message='Price has to be <= 10.')])
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = ItemModel
fields = '__all__'
class ValidatorMessageTests(TestCase):
def test_min_value_validator_message_is_copied_from_model(self):
data = {'price': -1}
s = ItemSerializer(data=data, partial=True)
s.is_valid()
assert s.errors['price'] == ['Price has to be >= 0.']
def test_max_value_validator_message_is_copied_from_model(self):
data = {'price': 11}
s = ItemSerializer(data=data, partial=True)
s.is_valid()
assert s.errors['price'] == ['Price has to be <= 10.']