From c8609ba652e1752e690c9e27e02b3531589d0c2c Mon Sep 17 00:00:00 2001 From: Rense VanderHoek Date: Fri, 20 Feb 2015 16:31:12 +0100 Subject: [PATCH 1/3] Set field length/values as actual attributes. The SimpleMetadata class in metadata.py tries to getattr() attributes on a field. For this to work, max_length and min_length have to be actually set as an attribute. Did the same for min_value and max_value and added those two to SimpleMetadata.get_field_info --- rest_framework/fields.py | 58 ++++++++++++++++++++------------------ rest_framework/metadata.py | 8 +++++- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index a5348922a..561ec93c2 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -556,15 +556,15 @@ class CharField(Field): def __init__(self, **kwargs): self.allow_blank = kwargs.pop('allow_blank', False) self.trim_whitespace = kwargs.pop('trim_whitespace', True) - max_length = kwargs.pop('max_length', None) - min_length = kwargs.pop('min_length', None) + self.max_length = kwargs.pop('max_length', None) + self.min_length = kwargs.pop('min_length', None) super(CharField, self).__init__(**kwargs) - if max_length is not None: - message = self.error_messages['max_length'].format(max_length=max_length) - self.validators.append(MaxLengthValidator(max_length, message=message)) - if min_length is not None: - message = self.error_messages['min_length'].format(min_length=min_length) - self.validators.append(MinLengthValidator(min_length, message=message)) + if self.max_length is not None: + message = self.error_messages['max_length'].format(max_length=self.max_length) + self.validators.append(MaxLengthValidator(self.max_length, message=message)) + if self.min_length is not None: + message = self.error_messages['min_length'].format(min_length=self.min_length) + self.validators.append(MinLengthValidator(self.min_length, message=message)) def run_validation(self, data=empty): # Test for the empty string here so that it does not get validated, @@ -658,15 +658,15 @@ class IntegerField(Field): MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. def __init__(self, **kwargs): - max_value = kwargs.pop('max_value', None) - min_value = kwargs.pop('min_value', None) + self.max_value = kwargs.pop('max_value', None) + self.min_value = kwargs.pop('min_value', None) super(IntegerField, self).__init__(**kwargs) - if max_value is not None: - message = self.error_messages['max_value'].format(max_value=max_value) - self.validators.append(MaxValueValidator(max_value, message=message)) - if min_value is not None: - message = self.error_messages['min_value'].format(min_value=min_value) - self.validators.append(MinValueValidator(min_value, message=message)) + if self.max_value is not None: + message = self.error_messages['max_value'].format(max_value=self.max_value) + self.validators.append(MaxValueValidator(self.max_value, message=message)) + if self.min_value is not None: + message = self.error_messages['min_value'].format(min_value=self.min_value) + self.validators.append(MinValueValidator(self.min_value, message=message)) def to_internal_value(self, data): if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH: @@ -692,15 +692,15 @@ class FloatField(Field): MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. def __init__(self, **kwargs): - max_value = kwargs.pop('max_value', None) - min_value = kwargs.pop('min_value', None) + self.max_value = kwargs.pop('max_value', None) + self.min_value = kwargs.pop('min_value', None) super(FloatField, self).__init__(**kwargs) - if max_value is not None: - message = self.error_messages['max_value'].format(max_value=max_value) - self.validators.append(MaxValueValidator(max_value, message=message)) - if min_value is not None: - message = self.error_messages['min_value'].format(min_value=min_value) - self.validators.append(MinValueValidator(min_value, message=message)) + if self.max_value is not None: + message = self.error_messages['max_value'].format(max_value=self.max_value) + self.validators.append(MaxValueValidator(self.max_value, message=message)) + if self.min_value is not None: + message = self.error_messages['min_value'].format(min_value=self.min_value) + self.validators.append(MinValueValidator(self.min_value, message=message)) def to_internal_value(self, data): if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH: @@ -733,12 +733,14 @@ class DecimalField(Field): self.max_digits = max_digits self.decimal_places = decimal_places self.coerce_to_string = coerce_to_string if (coerce_to_string is not None) else self.coerce_to_string + self.max_value = kwargs.pop('max_value', None) + self.min_value = kwargs.pop('min_value', None) super(DecimalField, self).__init__(**kwargs) - if max_value is not None: - message = self.error_messages['max_value'].format(max_value=max_value) + if self.max_value is not None: + message = self.error_messages['max_value'].format(max_value=self.max_value) self.validators.append(MaxValueValidator(max_value, message=message)) - if min_value is not None: - message = self.error_messages['min_value'].format(min_value=min_value) + if self.min_value is not None: + message = self.error_messages['min_value'].format(min_value=self.min_value) self.validators.append(MinValueValidator(min_value, message=message)) def to_internal_value(self, data): diff --git a/rest_framework/metadata.py b/rest_framework/metadata.py index 3b058fabb..bf3611aa3 100644 --- a/rest_framework/metadata.py +++ b/rest_framework/metadata.py @@ -115,7 +115,13 @@ class SimpleMetadata(BaseMetadata): field_info['type'] = self.label_lookup[field] field_info['required'] = getattr(field, 'required', False) - for attr in ['read_only', 'label', 'help_text', 'min_length', 'max_length']: + attrs = [ + 'read_only', 'label', 'help_text', + 'min_length', 'max_length', + 'min_value', 'max_value' + ] + + for attr in attrs: value = getattr(field, attr, None) if value is not None and value != '': field_info[attr] = force_text(value, strings_only=True) From 9cb547b85f547ef3b48f45710aee43c7cdd8b547 Mon Sep 17 00:00:00 2001 From: Rense VanderHoek Date: Fri, 20 Feb 2015 17:34:49 +0100 Subject: [PATCH 2/3] Validator-fix, added min/max fields to test_metadata --- rest_framework/fields.py | 4 ++-- tests/test_metadata.py | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 561ec93c2..1474f1db4 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -738,10 +738,10 @@ class DecimalField(Field): super(DecimalField, self).__init__(**kwargs) if self.max_value is not None: message = self.error_messages['max_value'].format(max_value=self.max_value) - self.validators.append(MaxValueValidator(max_value, message=message)) + self.validators.append(MaxValueValidator(self.max_value, message=message)) if self.min_value is not None: message = self.error_messages['min_value'].format(min_value=self.min_value) - self.validators.append(MinValueValidator(min_value, message=message)) + self.validators.append(MinValueValidator(self.min_value, message=message)) def to_internal_value(self, data): """ diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 5031c0f30..3a435f02f 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -54,8 +54,12 @@ class TestMetadata: """ class ExampleSerializer(serializers.Serializer): choice_field = serializers.ChoiceField(['red', 'green', 'blue']) - integer_field = serializers.IntegerField(max_value=10) - char_field = serializers.CharField(required=False) + integer_field = serializers.IntegerField( + min_value=1, max_value=1000 + ) + char_field = serializers.CharField( + required=False, min_length=3, max_length=40 + ) class ExampleView(views.APIView): """Example view.""" @@ -96,13 +100,18 @@ class TestMetadata: 'type': 'integer', 'required': True, 'read_only': False, - 'label': 'Integer field' + 'label': 'Integer field', + 'min_value': 1, + 'max_value': 1000, + }, 'char_field': { 'type': 'string', 'required': False, 'read_only': False, - 'label': 'Char field' + 'label': 'Char field', + 'min_length': 3, + 'max_length': 40 } } } From 91416632a86f518a043ac1b82da3d1774701ba96 Mon Sep 17 00:00:00 2001 From: Rense VanderHoek Date: Sat, 21 Feb 2015 12:31:37 +0100 Subject: [PATCH 3/3] DecimalField fix max_value and min_value are not in kwargs --- rest_framework/fields.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 1474f1db4..13ea6dde7 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -733,9 +733,12 @@ class DecimalField(Field): self.max_digits = max_digits self.decimal_places = decimal_places self.coerce_to_string = coerce_to_string if (coerce_to_string is not None) else self.coerce_to_string - self.max_value = kwargs.pop('max_value', None) - self.min_value = kwargs.pop('min_value', None) + + self.max_value = max_value + self.min_value = min_value + super(DecimalField, self).__init__(**kwargs) + if self.max_value is not None: message = self.error_messages['max_value'].format(max_value=self.max_value) self.validators.append(MaxValueValidator(self.max_value, message=message))