From 77e3021fea3e30382b9770eac25371495e0b156b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 20 Dec 2014 16:26:51 +0000 Subject: Better behaviour with null and '' for blank HTML fields. --- rest_framework/fields.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index c40dc3fb..aab80982 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -273,7 +273,11 @@ class Field(object): return empty return self.default_empty_html ret = dictionary[self.field_name] - return self.default_empty_html if (ret == '') else ret + if ret == '' and self.allow_null: + # If the field is blank, and null is a valid value then + # determine if we should use null instead. + return '' if getattr(self, 'allow_blank', False) else None + return ret return dictionary.get(self.field_name, empty) def get_attribute(self, instance): @@ -545,8 +549,6 @@ class CharField(Field): 'min_length': _('Ensure this field has at least {min_length} characters.') } initial = '' - coerce_blank_to_null = False - default_empty_html = '' def __init__(self, **kwargs): self.allow_blank = kwargs.pop('allow_blank', False) @@ -560,11 +562,6 @@ class CharField(Field): message = self.error_messages['min_length'].format(min_length=min_length) self.validators.append(MinLengthValidator(min_length, message=message)) - if self.allow_null and (not self.allow_blank) and (self.default is empty): - # HTML input cannot represent `None` values, so we need to - # forcibly coerce empty HTML values to `None` if `allow_null=True`. - self.default_empty_html = None - def run_validation(self, data=empty): # Test for the empty string here so that it does not get validated, # and so that subclasses do not need to handle it explicitly -- cgit v1.2.3 From a90ba2bc11de5fb391b95d4fce84f87ae7f88eff Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 31 Dec 2014 13:03:16 +0000 Subject: update error messages for language and consistency --- rest_framework/fields.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index c40dc3fb..0ff2b073 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -640,7 +640,7 @@ class IntegerField(Field): 'invalid': _('A valid integer 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}.'), - 'max_string_length': _('String value too large') + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -674,7 +674,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}.'), - 'max_string_length': _('String value too large') + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -710,7 +710,7 @@ class DecimalField(Field): '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_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), - 'max_string_length': _('String value too large') + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -793,7 +793,7 @@ class DecimalField(Field): class DateTimeField(Field): default_error_messages = { - 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}'), + 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), 'date': _('Expected a datetime but got a date.'), } format = api_settings.DATETIME_FORMAT @@ -858,7 +858,7 @@ class DateTimeField(Field): class DateField(Field): default_error_messages = { - 'invalid': _('Date has wrong format. Use one of these formats instead: {format}'), + 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), 'datetime': _('Expected a date but got a datetime.'), } format = api_settings.DATE_FORMAT @@ -916,7 +916,7 @@ class DateField(Field): class TimeField(Field): default_error_messages = { - 'invalid': _('Time has wrong format. Use one of these formats instead: {format}'), + 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), } format = api_settings.TIME_FORMAT input_formats = api_settings.TIME_INPUT_FORMATS @@ -1093,8 +1093,7 @@ class FileField(Field): class ImageField(FileField): default_error_messages = { 'invalid_image': _( - 'Upload a valid image. The file you uploaded was either not an ' - 'image or a corrupted image.' + 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.' ), } @@ -1119,7 +1118,7 @@ class ListField(Field): child = None initial = [] default_error_messages = { - 'not_a_list': _('Expected a list of items but got type `{input_type}`') + 'not_a_list': _('Expected a list of items but got type `{input_type}`.') } def __init__(self, *args, **kwargs): -- cgit v1.2.3 From b6ca7248ebcf95a95e1911aa0b130f653b8bf690 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 5 Jan 2015 14:32:12 +0000 Subject: required=False allows omission of value for output. Closes #2342 --- rest_framework/fields.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index aab80982..cc9410aa 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -288,6 +288,8 @@ class Field(object): try: return get_attribute(instance, self.source_attrs) except (KeyError, AttributeError) as exc: + if not self.required and self.default is empty: + raise SkipField() msg = ( 'Got {exc_type} when attempting to get a value for field ' '`{field}` on serializer `{serializer}`.\nThe serializer ' -- cgit v1.2.3 From 4c32083b8b59a50877633910055313dad7bb117e Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 12:01:11 +0000 Subject: use double quotes for user visible strings; end user visible strings in full stops; add some missing translation tags --- rest_framework/fields.py | 68 ++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 0ff2b073..8a781b35 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -149,8 +149,8 @@ class Field(object): _creation_counter = 0 default_error_messages = { - 'required': _('This field is required.'), - 'null': _('This field may not be null.') + 'required': _("This field is required."), + 'null': _("This field may not be null.") } default_validators = [] default_empty_html = empty @@ -477,7 +477,7 @@ class Field(object): class BooleanField(Field): default_error_messages = { - 'invalid': _('`{input}` is not a valid boolean.') + 'invalid': _("`{input}` is not a valid boolean.") } default_empty_html = False initial = False @@ -505,7 +505,7 @@ class BooleanField(Field): class NullBooleanField(Field): default_error_messages = { - 'invalid': _('`{input}` is not a valid boolean.') + 'invalid': _("`{input}` is not a valid boolean.") } initial = None TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True)) @@ -540,9 +540,9 @@ class NullBooleanField(Field): class CharField(Field): default_error_messages = { - 'blank': _('This field may not be blank.'), - 'max_length': _('Ensure this field has no more than {max_length} characters.'), - 'min_length': _('Ensure this field has at least {min_length} characters.') + 'blank': _("This field may not be blank."), + 'max_length': _("Ensure this field has no more than {max_length} characters."), + 'min_length': _("Ensure this field has at least {min_length} characters.") } initial = '' coerce_blank_to_null = False @@ -584,7 +584,7 @@ class CharField(Field): class EmailField(CharField): default_error_messages = { - 'invalid': _('Enter a valid email address.') + 'invalid': _("Enter a valid email address.") } def __init__(self, **kwargs): @@ -601,7 +601,7 @@ class EmailField(CharField): class RegexField(CharField): default_error_messages = { - 'invalid': _('This value does not match the required pattern.') + 'invalid': _("This value does not match the required pattern.") } def __init__(self, regex, **kwargs): @@ -637,10 +637,10 @@ class URLField(CharField): class IntegerField(Field): default_error_messages = { - 'invalid': _('A valid integer 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}.'), - 'max_string_length': _('String value too large.') + 'invalid': _("A valid integer 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}."), + 'max_string_length': _("String value too large.") } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -672,9 +672,9 @@ class IntegerField(Field): class FloatField(Field): default_error_messages = { '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}.'), - 'max_string_length': _('String value too large.') + '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}."), + 'max_string_length': _("String value too large.") } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -704,13 +704,13 @@ class FloatField(Field): class DecimalField(Field): default_error_messages = { - '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}.'), - '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_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), - 'max_string_length': _('String value too large.') + '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}."), + '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_whole_digits': _("Ensure that there are no more than {max_whole_digits} digits before the decimal point."), + 'max_string_length': _("String value too large.") } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -793,8 +793,8 @@ class DecimalField(Field): class DateTimeField(Field): default_error_messages = { - 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), - 'date': _('Expected a datetime but got a date.'), + 'invalid': _("Datetime has wrong format. Use one of these formats instead: {format}."), + 'date': _("Expected a datetime but got a date."), } format = api_settings.DATETIME_FORMAT input_formats = api_settings.DATETIME_INPUT_FORMATS @@ -858,8 +858,8 @@ class DateTimeField(Field): class DateField(Field): default_error_messages = { - 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), - 'datetime': _('Expected a date but got a datetime.'), + 'invalid': _("Date has wrong format. Use one of these formats instead: {format}."), + 'datetime': _("Expected a date but got a datetime."), } format = api_settings.DATE_FORMAT input_formats = api_settings.DATE_INPUT_FORMATS @@ -916,7 +916,7 @@ class DateField(Field): class TimeField(Field): default_error_messages = { - 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), + 'invalid': _("Time has wrong format. Use one of these formats instead: {format}."), } format = api_settings.TIME_FORMAT input_formats = api_settings.TIME_INPUT_FORMATS @@ -972,7 +972,7 @@ class TimeField(Field): class ChoiceField(Field): default_error_messages = { - 'invalid_choice': _('`{input}` is not a valid choice.') + 'invalid_choice': _("`{input}` is not a valid choice.") } def __init__(self, choices, **kwargs): @@ -1016,8 +1016,8 @@ class ChoiceField(Field): class MultipleChoiceField(ChoiceField): default_error_messages = { - 'invalid_choice': _('`{input}` is not a valid choice.'), - 'not_a_list': _('Expected a list of items but got type `{input_type}`.') + 'invalid_choice': _("`{input}` is not a valid choice."), + 'not_a_list': _("Expected a list of items but got type `{input_type}`.") } default_empty_html = [] @@ -1051,7 +1051,7 @@ class FileField(Field): 'invalid': _("The submitted data was not a file. Check the encoding type on the form."), 'no_name': _("No filename could be determined."), 'empty': _("The submitted file is empty."), - 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), + 'max_length': _("Ensure this filename has at most {max_length} characters (it has {length})."), } use_url = api_settings.UPLOADED_FILES_USE_URL @@ -1118,7 +1118,7 @@ class ListField(Field): child = None initial = [] default_error_messages = { - 'not_a_list': _('Expected a list of items but got type `{input_type}`.') + 'not_a_list': _("Expected a list of items but got type `{input_type}`.") } def __init__(self, *args, **kwargs): @@ -1249,7 +1249,7 @@ class ModelField(Field): that do not have a serializer field to be mapped to. """ default_error_messages = { - 'max_length': _('Ensure this field has no more than {max_length} characters.'), + 'max_length': _("Ensure this field has no more than {max_length} characters."), } def __init__(self, model_field, **kwargs): -- cgit v1.2.3 From 9a4267049ba37883e3e0c21b5d453b9551343b8d Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 12:33:37 +0000 Subject: use double quotes in user messages --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 8a781b35..27944608 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -612,7 +612,7 @@ class RegexField(CharField): class SlugField(CharField): default_error_messages = { - 'invalid': _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.") + 'invalid': _("Enter a valid \"slug\" consisting of letters, numbers, underscores or hyphens.") } def __init__(self, **kwargs): -- cgit v1.2.3 From 91e316f7810157474d6246cd0024bd7f7cc31ff7 Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 12:46:23 +0000 Subject: prefer single quotes in source and double quotes in user visible strings; add some missing full stops to user visible strings --- rest_framework/fields.py | 82 ++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 27944608..76101608 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -149,8 +149,8 @@ class Field(object): _creation_counter = 0 default_error_messages = { - 'required': _("This field is required."), - 'null': _("This field may not be null.") + 'required': _('This field is required.'), + 'null': _('This field may not be null.') } default_validators = [] default_empty_html = empty @@ -477,7 +477,7 @@ class Field(object): class BooleanField(Field): default_error_messages = { - 'invalid': _("`{input}` is not a valid boolean.") + 'invalid': _('`{input}` is not a valid boolean.') } default_empty_html = False initial = False @@ -505,7 +505,7 @@ class BooleanField(Field): class NullBooleanField(Field): default_error_messages = { - 'invalid': _("`{input}` is not a valid boolean.") + 'invalid': _('`{input}` is not a valid boolean.') } initial = None TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True)) @@ -540,9 +540,9 @@ class NullBooleanField(Field): class CharField(Field): default_error_messages = { - 'blank': _("This field may not be blank."), - 'max_length': _("Ensure this field has no more than {max_length} characters."), - 'min_length': _("Ensure this field has at least {min_length} characters.") + 'blank': _('This field may not be blank.'), + 'max_length': _('Ensure this field has no more than {max_length} characters.'), + 'min_length': _('Ensure this field has at least {min_length} characters.') } initial = '' coerce_blank_to_null = False @@ -584,7 +584,7 @@ class CharField(Field): class EmailField(CharField): default_error_messages = { - 'invalid': _("Enter a valid email address.") + 'invalid': _('Enter a valid email address.') } def __init__(self, **kwargs): @@ -601,7 +601,7 @@ class EmailField(CharField): class RegexField(CharField): default_error_messages = { - 'invalid': _("This value does not match the required pattern.") + 'invalid': _('This value does not match the required pattern.') } def __init__(self, regex, **kwargs): @@ -612,7 +612,7 @@ class RegexField(CharField): class SlugField(CharField): default_error_messages = { - 'invalid': _("Enter a valid \"slug\" consisting of letters, numbers, underscores or hyphens.") + 'invalid': _('Enter a valid "slug" consisting of letters, numbers, underscores or hyphens.') } def __init__(self, **kwargs): @@ -624,7 +624,7 @@ class SlugField(CharField): class URLField(CharField): default_error_messages = { - 'invalid': _("Enter a valid URL.") + 'invalid': _('Enter a valid URL.') } def __init__(self, **kwargs): @@ -637,10 +637,10 @@ class URLField(CharField): class IntegerField(Field): default_error_messages = { - 'invalid': _("A valid integer 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}."), - 'max_string_length': _("String value too large.") + 'invalid': _('A valid integer 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}.'), + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -671,10 +671,10 @@ class IntegerField(Field): class FloatField(Field): default_error_messages = { - '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}."), - 'max_string_length': _("String value too large.") + '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}.'), + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -704,13 +704,13 @@ class FloatField(Field): class DecimalField(Field): default_error_messages = { - '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}."), - '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_whole_digits': _("Ensure that there are no more than {max_whole_digits} digits before the decimal point."), - 'max_string_length': _("String value too large.") + '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}.'), + '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_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), + 'max_string_length': _('String value too large.') } MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. @@ -793,8 +793,8 @@ class DecimalField(Field): class DateTimeField(Field): default_error_messages = { - 'invalid': _("Datetime has wrong format. Use one of these formats instead: {format}."), - 'date': _("Expected a datetime but got a date."), + 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), + 'date': _('Expected a datetime but got a date.'), } format = api_settings.DATETIME_FORMAT input_formats = api_settings.DATETIME_INPUT_FORMATS @@ -858,8 +858,8 @@ class DateTimeField(Field): class DateField(Field): default_error_messages = { - 'invalid': _("Date has wrong format. Use one of these formats instead: {format}."), - 'datetime': _("Expected a date but got a datetime."), + 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), + 'datetime': _('Expected a date but got a datetime.'), } format = api_settings.DATE_FORMAT input_formats = api_settings.DATE_INPUT_FORMATS @@ -916,7 +916,7 @@ class DateField(Field): class TimeField(Field): default_error_messages = { - 'invalid': _("Time has wrong format. Use one of these formats instead: {format}."), + 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), } format = api_settings.TIME_FORMAT input_formats = api_settings.TIME_INPUT_FORMATS @@ -972,7 +972,7 @@ class TimeField(Field): class ChoiceField(Field): default_error_messages = { - 'invalid_choice': _("`{input}` is not a valid choice.") + 'invalid_choice': _('`{input}` is not a valid choice.') } def __init__(self, choices, **kwargs): @@ -1016,8 +1016,8 @@ class ChoiceField(Field): class MultipleChoiceField(ChoiceField): default_error_messages = { - 'invalid_choice': _("`{input}` is not a valid choice."), - 'not_a_list': _("Expected a list of items but got type `{input_type}`.") + 'invalid_choice': _('`{input}` is not a valid choice.'), + 'not_a_list': _('Expected a list of items but got type `{input_type}`.') } default_empty_html = [] @@ -1047,11 +1047,11 @@ class MultipleChoiceField(ChoiceField): class FileField(Field): default_error_messages = { - 'required': _("No file was submitted."), - 'invalid': _("The submitted data was not a file. Check the encoding type on the form."), - 'no_name': _("No filename could be determined."), - 'empty': _("The submitted file is empty."), - 'max_length': _("Ensure this filename has at most {max_length} characters (it has {length})."), + 'required': _('No file was submitted.'), + 'invalid': _('The submitted data was not a file. Check the encoding type on the form.'), + 'no_name': _('No filename could be determined.'), + 'empty': _('The submitted file is empty.'), + 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), } use_url = api_settings.UPLOADED_FILES_USE_URL @@ -1118,7 +1118,7 @@ class ListField(Field): child = None initial = [] default_error_messages = { - 'not_a_list': _("Expected a list of items but got type `{input_type}`.") + 'not_a_list': _('Expected a list of items but got type `{input_type}`.') } def __init__(self, *args, **kwargs): @@ -1249,7 +1249,7 @@ class ModelField(Field): that do not have a serializer field to be mapped to. """ default_error_messages = { - 'max_length': _("Ensure this field has no more than {max_length} characters."), + 'max_length': _('Ensure this field has no more than {max_length} characters.'), } def __init__(self, model_field, **kwargs): -- cgit v1.2.3 From 58ec7669aed9ebd58fd6095c6a6437bf9f3cf7f1 Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 18:22:30 +0000 Subject: swap backticks for double quotes --- rest_framework/fields.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 76101608..b80dea60 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -477,7 +477,7 @@ class Field(object): class BooleanField(Field): default_error_messages = { - 'invalid': _('`{input}` is not a valid boolean.') + 'invalid': _('"{input}" is not a valid boolean.') } default_empty_html = False initial = False @@ -505,7 +505,7 @@ class BooleanField(Field): class NullBooleanField(Field): default_error_messages = { - 'invalid': _('`{input}` is not a valid boolean.') + 'invalid': _('"{input}" is not a valid boolean.') } initial = None TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True)) @@ -972,7 +972,7 @@ class TimeField(Field): class ChoiceField(Field): default_error_messages = { - 'invalid_choice': _('`{input}` is not a valid choice.') + 'invalid_choice': _('"{input}" is not a valid choice.') } def __init__(self, choices, **kwargs): @@ -1016,8 +1016,8 @@ class ChoiceField(Field): class MultipleChoiceField(ChoiceField): default_error_messages = { - 'invalid_choice': _('`{input}` is not a valid choice.'), - 'not_a_list': _('Expected a list of items but got type `{input_type}`.') + 'invalid_choice': _('"{input}" is not a valid choice.'), + 'not_a_list': _('Expected a list of items but got type "{input_type}".') } default_empty_html = [] @@ -1118,7 +1118,7 @@ class ListField(Field): child = None initial = [] default_error_messages = { - 'not_a_list': _('Expected a list of items but got type `{input_type}`.') + 'not_a_list': _('Expected a list of items but got type "{input_type}".') } def __init__(self, *args, **kwargs): -- cgit v1.2.3 From e8db1834d3a3f6ba05276b64e5681288aa8f9820 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 23 Jan 2015 15:24:06 +0000 Subject: Added UUIDField. --- rest_framework/fields.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index cc9410aa..5e3f7ce4 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -23,6 +23,7 @@ import datetime import decimal import inspect import re +import uuid class empty: @@ -632,6 +633,23 @@ class URLField(CharField): self.validators.append(validator) +class UUIDField(Field): + default_error_messages = { + 'invalid': _('"{value}" is not a valid UUID.'), + } + + def to_internal_value(self, data): + if not isinstance(data, uuid.UUID): + try: + return uuid.UUID(data) + except (ValueError, TypeError): + self.fail('invalid', value=data) + return data + + def to_representation(self, value): + return str(value) + + # Number types... class IntegerField(Field): -- cgit v1.2.3 From 35f6a8246299d31ecce4f791f9527bf34cebe6e2 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 23 Jan 2015 16:27:23 +0000 Subject: Added DictField and support for HStoreField. --- rest_framework/fields.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 5e3f7ce4..71a9f193 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1132,8 +1132,21 @@ class ImageField(FileField): # Composite field types... +class _UnvalidatedField(Field): + def __init__(self, *args, **kwargs): + super(_UnvalidatedField, self).__init__(*args, **kwargs) + self.allow_blank = True + self.allow_null = True + + def to_internal_value(self, data): + return data + + def to_representation(self, value): + return value + + class ListField(Field): - child = None + child = _UnvalidatedField() initial = [] default_error_messages = { 'not_a_list': _('Expected a list of items but got type `{input_type}`') @@ -1141,7 +1154,6 @@ class ListField(Field): def __init__(self, *args, **kwargs): self.child = kwargs.pop('child', copy.deepcopy(self.child)) - assert self.child is not None, '`child` is a required argument.' assert not inspect.isclass(self.child), '`child` has not been instantiated.' super(ListField, self).__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) @@ -1170,6 +1182,49 @@ class ListField(Field): return [self.child.to_representation(item) for item in data] +class DictField(Field): + child = _UnvalidatedField() + initial = [] + default_error_messages = { + 'not_a_dict': _('Expected a dictionary of items but got type `{input_type}`') + } + + def __init__(self, *args, **kwargs): + self.child = kwargs.pop('child', copy.deepcopy(self.child)) + assert not inspect.isclass(self.child), '`child` has not been instantiated.' + super(DictField, self).__init__(*args, **kwargs) + self.child.bind(field_name='', parent=self) + + def get_value(self, dictionary): + # We override the default field access in order to support + # lists in HTML forms. + if html.is_html_input(dictionary): + return html.parse_html_list(dictionary, prefix=self.field_name) + return dictionary.get(self.field_name, empty) + + def to_internal_value(self, data): + """ + Dicts of native values <- Dicts of primitive datatypes. + """ + if html.is_html_input(data): + data = html.parse_html_dict(data) + if not isinstance(data, dict): + self.fail('not_a_dict', input_type=type(data).__name__) + return dict([ + (six.text_type(key), self.child.run_validation(value)) + for key, value in data.items() + ]) + + def to_representation(self, value): + """ + List of object instances -> List of dicts of primitive datatypes. + """ + return dict([ + (six.text_type(key), self.child.to_representation(val)) + for key, val in value.items() + ]) + + # Miscellaneous field types... class ReadOnlyField(Field): -- cgit v1.2.3