From afb3f8ab0ad6c33b147292e9777ba0ddf3871d14 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 22 Sep 2014 13:26:47 +0100 Subject: [PATCH] Tests and tweaks for text fields --- rest_framework/fields.py | 32 ++++++++++---- tests/test_fields.py | 93 +++++++++++++++++++++++++++++++++++----- 2 files changed, 107 insertions(+), 18 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index db75ddf91..35bd5c4b4 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -12,6 +12,7 @@ from rest_framework.utils import html, representation, humanize_datetime import datetime import decimal import inspect +import re class empty: @@ -325,7 +326,11 @@ class EmailField(CharField): default_error_messages = { 'invalid': _('Enter a valid email address.') } - default_validators = [validators.validate_email] + + def __init__(self, **kwargs): + super(EmailField, self).__init__(**kwargs) + validator = validators.EmailValidator(message=self.error_messages['invalid']) + self.validators = [validator] + self.validators def to_internal_value(self, data): if data == '' and not self.allow_blank: @@ -341,26 +346,37 @@ class EmailField(CharField): class RegexField(CharField): + default_error_messages = { + 'invalid': _('This value does not match the required pattern.') + } + def __init__(self, regex, **kwargs): - kwargs['validators'] = ( - [validators.RegexValidator(regex)] + - kwargs.get('validators', []) - ) super(RegexField, self).__init__(**kwargs) + validator = validators.RegexValidator(regex, message=self.error_messages['invalid']) + self.validators = [validator] + self.validators class SlugField(CharField): default_error_messages = { 'invalid': _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.") } - default_validators = [validators.validate_slug] + + def __init__(self, **kwargs): + super(SlugField, self).__init__(**kwargs) + slug_regex = re.compile(r'^[-a-zA-Z0-9_]+$') + validator = validators.RegexValidator(slug_regex, message=self.error_messages['invalid']) + self.validators = [validator] + self.validators class URLField(CharField): default_error_messages = { 'invalid': _("Enter a valid URL.") } - default_validators = [validators.URLValidator()] + + def __init__(self, **kwargs): + super(URLField, self).__init__(**kwargs) + validator = validators.URLValidator(message=self.error_messages['invalid']) + self.validators = [validator] + self.validators # Number types... @@ -642,7 +658,7 @@ class TimeField(Field): self.input_formats = input_formats if input_formats is not None else self.input_formats super(TimeField, self).__init__(*args, **kwargs) - def from_native(self, value): + def to_internal_value(self, value): if value in (None, ''): return None diff --git a/tests/test_fields.py b/tests/test_fields.py index 6ec18041c..ae7f19193 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -26,16 +26,7 @@ class ValidAndInvalidValues: assert exc_info.value.messages == expected_failure -class TestCharField(ValidAndInvalidValues): - valid_mappings = { - 1: '1', - 'abc': 'abc' - } - invalid_mappings = { - '': ['This field may not be blank.'] - } - field = fields.CharField() - +# Boolean types... class TestBooleanField(ValidAndInvalidValues): valid_mappings = { @@ -54,6 +45,60 @@ class TestBooleanField(ValidAndInvalidValues): field = fields.BooleanField() +# String types... + +class TestCharField(ValidAndInvalidValues): + valid_mappings = { + 1: '1', + 'abc': 'abc' + } + invalid_mappings = { + '': ['This field may not be blank.'] + } + field = fields.CharField() + + +class TestEmailField(ValidAndInvalidValues): + valid_mappings = { + 'example@example.com': 'example@example.com', + ' example@example.com ': 'example@example.com', + } + invalid_mappings = { + 'example.com': ['Enter a valid email address.'] + } + field = fields.EmailField() + + +class TestRegexField(ValidAndInvalidValues): + valid_mappings = { + 'a9': 'a9', + } + invalid_mappings = { + 'A9': ["This value does not match the required pattern."] + } + field = fields.RegexField(regex='[a-z][0-9]') + + +class TestSlugField(ValidAndInvalidValues): + valid_mappings = { + 'slug-99': 'slug-99', + } + invalid_mappings = { + 'slug 99': ["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."] + } + field = fields.SlugField() + + +class TestURLField(ValidAndInvalidValues): + valid_mappings = { + 'http://example.com': 'http://example.com', + } + invalid_mappings = { + 'example.com': ['Enter a valid URL.'] + } + field = fields.URLField() + + # Number types... class TestIntegerField(ValidAndInvalidValues): @@ -249,6 +294,34 @@ class TestNaiveDateTimeField(ValidAndInvalidValues): field = fields.DateTimeField(default_timezone=None) +class TestTimeField(ValidAndInvalidValues): + """ + Valid and invalid values for `TimeField`. + """ + valid_mappings = { + '13:00': datetime.time(13, 00), + datetime.time(13, 00): datetime.time(13, 00), + } + invalid_mappings = { + 'abc': ['Time has wrong format. Use one of these formats instead: hh:mm[:ss[.uuuuuu]]'], + '99:99': ['Time has wrong format. Use one of these formats instead: hh:mm[:ss[.uuuuuu]]'], + } + field = fields.TimeField() + + +class TestCustomInputFormatTimeField(ValidAndInvalidValues): + """ + Valid and invalid values for `TimeField` with a custom input format. + """ + valid_mappings = { + '1:00pm': datetime.time(13, 00), + } + invalid_mappings = { + '13:00': ['Time has wrong format. Use one of these formats instead: hh:mm[AM|PM]'], + } + field = fields.TimeField(input_formats=['%I:%M%p']) + + # Choice types... class TestChoiceField(ValidAndInvalidValues):