From 9157db5da0b5601793d1a9f24e9cb10670a82be2 Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Tue, 26 Feb 2013 11:09:54 +0100 Subject: Add better date / datetime validation (pull 2) addition to #631 with update to master + timefield support --- rest_framework/fields.py | 87 +++++------ rest_framework/tests/fields.py | 343 +++++++++++++++++++++++++++++++++++++++-- rest_framework/utils/dates.py | 14 ++ 3 files changed, 388 insertions(+), 56 deletions(-) create mode 100644 rest_framework/utils/dates.py (limited to 'rest_framework') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 86c3a837..2260c430 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -19,6 +19,7 @@ from rest_framework.compat import BytesIO from rest_framework.compat import six from rest_framework.compat import smart_text from rest_framework.compat import parse_time +from rest_framework.utils.dates import get_readable_date_format def is_simple_callable(obj): @@ -447,13 +448,14 @@ class DateField(WritableField): form_field_class = forms.DateField default_error_messages = { - 'invalid': _("'%s' value has an invalid date format. It must be " - "in YYYY-MM-DD format."), - 'invalid_date': _("'%s' value has the correct format (YYYY-MM-DD) " - "but it is an invalid date."), + 'invalid': _(u"Date has wrong format. Use one of these formats instead: %s"), } empty = None + def __init__(self, *args, **kwargs): + self.format = kwargs.pop('format', settings.DATE_INPUT_FORMATS) + super(DateField, self).__init__(*args, **kwargs) + def from_native(self, value): if value in validators.EMPTY_VALUES: return None @@ -468,15 +470,16 @@ class DateField(WritableField): if isinstance(value, datetime.date): return value - try: - parsed = parse_date(value) - if parsed is not None: - return parsed - except (ValueError, TypeError): - msg = self.error_messages['invalid_date'] % value - raise ValidationError(msg) + for format in self.format: + try: + parsed = datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + pass + else: + return parsed.date() - msg = self.error_messages['invalid'] % value + date_input_formats = '; '.join(self.format) + msg = self.error_messages['invalid'] % get_readable_date_format(date_input_formats) raise ValidationError(msg) @@ -486,16 +489,14 @@ class DateTimeField(WritableField): form_field_class = forms.DateTimeField default_error_messages = { - 'invalid': _("'%s' value has an invalid format. It must be in " - "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."), - 'invalid_date': _("'%s' value has the correct format " - "(YYYY-MM-DD) but it is an invalid date."), - 'invalid_datetime': _("'%s' value has the correct format " - "(YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) " - "but it is an invalid date/time."), + 'invalid': _(u"Datetime has wrong format. Use one of these formats instead: %s"), } empty = None + def __init__(self, *args, **kwargs): + self.format = kwargs.pop('format', settings.DATETIME_INPUT_FORMATS) + super(DateTimeField, self).__init__(*args, **kwargs) + def from_native(self, value): if value in validators.EMPTY_VALUES: return None @@ -516,23 +517,16 @@ class DateTimeField(WritableField): value = timezone.make_aware(value, default_timezone) return value - try: - parsed = parse_datetime(value) - if parsed is not None: + for format in self.format: + try: + parsed = datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + pass + else: return parsed - except (ValueError, TypeError): - msg = self.error_messages['invalid_datetime'] % value - raise ValidationError(msg) - try: - parsed = parse_date(value) - if parsed is not None: - return datetime.datetime(parsed.year, parsed.month, parsed.day) - except (ValueError, TypeError): - msg = self.error_messages['invalid_date'] % value - raise ValidationError(msg) - - msg = self.error_messages['invalid'] % value + datetime_input_formats = '; '.join(self.format) + msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats) raise ValidationError(msg) @@ -542,11 +536,14 @@ class TimeField(WritableField): form_field_class = forms.TimeField default_error_messages = { - 'invalid': _("'%s' value has an invalid format. It must be a valid " - "time in the HH:MM[:ss[.uuuuuu]] format."), + 'invalid': _(u"Time has wrong format. Use one of these formats instead: %s"), } empty = None + def __init__(self, *args, **kwargs): + self.format = kwargs.pop('format', settings.TIME_INPUT_FORMATS) + super(TimeField, self).__init__(*args, **kwargs) + def from_native(self, value): if value in validators.EMPTY_VALUES: return None @@ -554,13 +551,17 @@ class TimeField(WritableField): if isinstance(value, datetime.time): return value - try: - parsed = parse_time(value) - assert parsed is not None - return parsed - except (ValueError, TypeError): - msg = self.error_messages['invalid'] % value - raise ValidationError(msg) + for format in self.format: + try: + parsed = datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + pass + else: + return parsed.time() + + time_input_formats = '; '.join(self.format) + msg = self.error_messages['invalid'] % get_readable_date_format(time_input_formats) + raise ValidationError(msg) class IntegerField(WritableField): diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index 840ed320..37517642 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -3,9 +3,13 @@ General serializer field tests. """ from __future__ import unicode_literals import datetime + +import django from django.db import models from django.test import TestCase from django.core import validators +from django.utils import unittest + from rest_framework import serializers @@ -18,6 +22,21 @@ class CharPrimaryKeyModel(models.Model): id = models.CharField(max_length=20, primary_key=True) +class DateObject(object): + def __init__(self, date): + self.date = date + + +class DateTimeObject(object): + def __init__(self, date_time): + self.date_time = date_time + + +class TimeObject(object): + def __init__(self, time): + self.time = time + + class TimestampedModelSerializer(serializers.ModelSerializer): class Meta: model = TimestampedModel @@ -28,6 +47,66 @@ class CharPrimaryKeyModelSerializer(serializers.ModelSerializer): model = CharPrimaryKeyModel +class DateObjectSerializer(serializers.Serializer): + date = serializers.DateField() + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.date = attrs['date'] + return instance + return DateObject(**attrs) + + +class DateObjectCustomFormatSerializer(serializers.Serializer): + date = serializers.DateField(format=("%Y", "%Y -- %m")) + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.date = attrs['date'] + return instance + return DateObject(**attrs) + + +class DateTimeObjectSerializer(serializers.Serializer): + date_time = serializers.DateTimeField() + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.date_time = attrs['date_time'] + return instance + return DateTimeObject(**attrs) + + +class DateTimeObjectCustomFormatSerializer(serializers.Serializer): + date_time = serializers.DateTimeField(format=("%Y", "%Y %H:%M")) + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.date_time = attrs['date_time'] + return instance + return DateTimeObject(**attrs) + + +class TimeObjectSerializer(serializers.Serializer): + time = serializers.TimeField() + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.time = attrs['time'] + return instance + return TimeObject(**attrs) + + +class TimeObjectCustomFormatSerializer(serializers.Serializer): + time = serializers.TimeField(format=("%H -- %M", "%H%M%S")) + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.time = attrs['time'] + return instance + return TimeObject(**attrs) + + class TimeFieldModel(models.Model): clock = models.TimeField() @@ -59,37 +138,275 @@ class BasicFieldTests(TestCase): serializer = CharPrimaryKeyModelSerializer() self.assertEqual(serializer.fields['id'].read_only, False) - def test_TimeField_from_native(self): + +class DateFieldTest(TestCase): + def test_valid_default_date_input_formats(self): + serializer = DateObjectSerializer(data={'date': '1984-07-31'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': '07/31/1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': '07/31/84'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': 'Jul 31 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': 'Jul 31, 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': '31 Jul 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': '31 Jul 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': 'July 31 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': 'July 31, 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': '31 July 1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectSerializer(data={'date': '31 July, 1984'}) + self.assertTrue(serializer.is_valid()) + + def test_valid_custom_date_input_formats(self): + serializer = DateObjectCustomFormatSerializer(data={'date': '1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateObjectCustomFormatSerializer(data={'date': '1984 -- 07'}) + self.assertTrue(serializer.is_valid()) + + def test_wrong_default_date_input_format(self): + serializer = DateObjectSerializer(data={'date': 'something wrong'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'date': [u'Date has wrong format. Use one of these formats instead: ' + u'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' + u'[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' + u'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' + u'[January through December] DD, YYYY; DD [January through December] YYYY; ' + u'DD [January through December], YYYY']}) + + def test_wrong_custom_date_input_format(self): + serializer = DateObjectCustomFormatSerializer(data={'date': '07/31/1984'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'date': [u'Date has wrong format. Use one of these formats instead: YYYY; YYYY -- MM']}) + + def test_from_native(self): + f = serializers.DateField() + result = f.from_native('1984-07-31') + + self.assertEqual(datetime.date(1984, 7, 31), result) + + def test_from_native_datetime_date(self): + """ + Make sure from_native() accepts a datetime.date instance. + """ + f = serializers.DateField() + result = f.from_native(datetime.date(1984, 7, 31)) + + self.assertEqual(result, datetime.date(1984, 7, 31)) + + def test_from_native_empty(self): + f = serializers.DateField() + result = f.from_native('') + + self.assertEqual(result, None) + + def test_from_native_invalid_date(self): + f = serializers.DateField() + + try: + f.from_native('1984-42-31') + except validators.ValidationError as e: + self.assertEqual(e.messages, [u'Date has wrong format. Use one of these formats instead: ' + u'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' + u'[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' + u'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' + u'[January through December] DD, YYYY; DD [January through December] YYYY; ' + u'DD [January through December], YYYY']) + else: + self.fail("ValidationError was not properly raised") + + +class DateTimeFieldTest(TestCase): + def test_valid_default_date_time_input_formats(self): + serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31 04:31:59'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31 04:31'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984 04:31:59'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984 04:31'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84 04:31:59'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84 04:31'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84'}) + self.assertTrue(serializer.is_valid()) + + @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") + def test_valid_default_date_time_input_formats_for_django_gte_1_4(self): + serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31 04:31:59.123456'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984 04:31:59.123456'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84 04:31:59.123456'}) + self.assertTrue(serializer.is_valid()) + + def test_valid_custom_date_time_input_formats(self): + serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '1984'}) + self.assertTrue(serializer.is_valid()) + + serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '1984 04:31'}) + self.assertTrue(serializer.is_valid()) + + @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") + def test_wrong_default_date_time_input_format_for_django_gte_1_4(self): + serializer = DateTimeObjectSerializer(data={'date_time': 'something wrong'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'date_time': [u'Datetime has wrong format. Use one of these formats instead: ' + u'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' + u'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' + u'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' + u'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']}) + + @unittest.skipUnless(django.VERSION < (1, 4), "django >= 1.4 have microseconds in default settings") + def test_wrong_default_date_time_input_format_for_django_lt_1_4(self): + serializer = DateTimeObjectSerializer(data={'date_time': 'something wrong'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'date_time': [u'Datetime has wrong format. Use one of these formats instead:' + u' YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' + u'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' + u'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']}) + + def test_wrong_custom_date_time_input_format(self): + serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '07/31/84 04:31'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'date_time': [u'Datetime has wrong format. Use one of these formats instead: YYYY; YYYY HH:MM']}) + + def test_from_native(self): + f = serializers.DateTimeField() + result = f.from_native('1984-07-31 04:31') + + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result) + + def test_from_native_datetime_datetime(self): + """ + Make sure from_native() accepts a datetime.date instance. + """ + f = serializers.DateTimeField() + result = f.from_native(datetime.datetime(1984, 7, 31)) + + self.assertEqual(result, datetime.datetime(1984, 7, 31)) + + def test_from_native_empty(self): + f = serializers.DateTimeField() + result = f.from_native('') + + self.assertEqual(result, None) + + @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") + def test_from_native_invalid_datetime(self): + f = serializers.DateTimeField() + + try: + f.from_native('1984-42-31 04:31') + except validators.ValidationError as e: + self.assertEqual(e.messages, [u'Datetime has wrong format. Use one of these formats instead: ' + u'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' + u'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' + u'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' + u'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']) + else: + self.fail("ValidationError was not properly raised") + + @unittest.skipUnless(django.VERSION < (1, 4), "django >= 1.4 have microseconds in default settings") + def test_from_native_invalid_datetime(self): + f = serializers.DateTimeField() + + try: + f.from_native('1984-42-31 04:31') + except validators.ValidationError as e: + self.assertEqual(e.messages, [u'Datetime has wrong format. Use one of these formats instead:' + u' YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' + u'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' + u'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']) + else: + self.fail("ValidationError was not properly raised") + + +class TimeFieldTest(TestCase): + def test_valid_default_time_input_formats(self): + serializer = TimeObjectSerializer(data={'time': '04:31'}) + self.assertTrue(serializer.is_valid()) + + serializer = TimeObjectSerializer(data={'time': '04:31:59'}) + self.assertTrue(serializer.is_valid()) + + def test_valid_custom_time_input_formats(self): + serializer = TimeObjectCustomFormatSerializer(data={'time': '04 -- 31'}) + self.assertTrue(serializer.is_valid()) + + serializer = TimeObjectCustomFormatSerializer(data={'time': '043159'}) + self.assertTrue(serializer.is_valid()) + + def test_wrong_default_time_input_format(self): + serializer = TimeObjectSerializer(data={'time': 'something wrong'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'time': [u'Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM']}) + + def test_wrong_custom_time_input_format(self): + serializer = TimeObjectCustomFormatSerializer(data={'time': '04:31'}) + self.assertFalse(serializer.is_valid()) + self.assertEquals(serializer.errors, {'time': [u'Time has wrong format. Use one of these formats instead: HH -- MM; HHMMSS']}) + + def test_from_native(self): f = serializers.TimeField() - result = f.from_native('12:34:56.987654') + result = f.from_native('12:34:56') - self.assertEqual(datetime.time(12, 34, 56, 987654), result) + self.assertEqual(datetime.time(12, 34, 56), result) - def test_TimeField_from_native_datetime_time(self): + def test_from_native_datetime_time(self): """ Make sure from_native() accepts a datetime.time instance. """ f = serializers.TimeField() result = f.from_native(datetime.time(12, 34, 56)) + self.assertEqual(result, datetime.time(12, 34, 56)) - def test_TimeField_from_native_empty(self): + def test_from_native_empty(self): f = serializers.TimeField() result = f.from_native('') + self.assertEqual(result, None) - def test_TimeField_from_native_invalid_time(self): + def test_from_native_invalid_time(self): f = serializers.TimeField() try: f.from_native('12:69:12') except validators.ValidationError as e: - self.assertEqual(e.messages, ["'12:69:12' value has an invalid " - "format. It must be a valid time " - "in the HH:MM[:ss[.uuuuuu]] format."]) + self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM"]) else: self.fail("ValidationError was not properly raised") - - def test_TimeFieldModelSerializer(self): - serializer = TimeFieldModelSerializer() - self.assertTrue(isinstance(serializer.fields['clock'], serializers.TimeField)) diff --git a/rest_framework/utils/dates.py b/rest_framework/utils/dates.py new file mode 100644 index 00000000..f094f72d --- /dev/null +++ b/rest_framework/utils/dates.py @@ -0,0 +1,14 @@ +def get_readable_date_format(date_format): + mapping = [("%Y", "YYYY"), + ("%y", "YY"), + ("%m", "MM"), + ("%b", "[Jan through Dec]"), + ("%B", "[January through December]"), + ("%d", "DD"), + ("%H", "HH"), + ("%M", "MM"), + ("%S", "SS"), + ("%f", "uuuuuu")] + for k, v in mapping: + date_format = date_format.replace(k, v) + return date_format \ No newline at end of file -- cgit v1.2.3 From b2165cc76a97ee09c0ff109df2140e2950549a19 Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Tue, 26 Feb 2013 11:35:39 +0100 Subject: Fix for python 3 support - thanks @Linovia --- rest_framework/fields.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 2260c430..d38b726a 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -448,7 +448,7 @@ class DateField(WritableField): form_field_class = forms.DateField default_error_messages = { - 'invalid': _(u"Date has wrong format. Use one of these formats instead: %s"), + 'invalid': _("Date has wrong format. Use one of these formats instead: %s"), } empty = None @@ -489,7 +489,7 @@ class DateTimeField(WritableField): form_field_class = forms.DateTimeField default_error_messages = { - 'invalid': _(u"Datetime has wrong format. Use one of these formats instead: %s"), + 'invalid': _("Datetime has wrong format. Use one of these formats instead: %s"), } empty = None @@ -536,7 +536,7 @@ class TimeField(WritableField): form_field_class = forms.TimeField default_error_messages = { - 'invalid': _(u"Time has wrong format. Use one of these formats instead: %s"), + 'invalid': _("Time has wrong format. Use one of these formats instead: %s"), } empty = None -- cgit v1.2.3 From ef5752f8b5de3f75310d654f3da649ad4a9a6db5 Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Tue, 26 Feb 2013 11:42:50 +0100 Subject: Fix for python 3 support --- rest_framework/tests/fields.py | 72 +++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index 37517642..a3429096 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -184,17 +184,17 @@ class DateFieldTest(TestCase): def test_wrong_default_date_input_format(self): serializer = DateObjectSerializer(data={'date': 'something wrong'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date': [u'Date has wrong format. Use one of these formats instead: ' - u'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' - u'[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' - u'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' - u'[January through December] DD, YYYY; DD [January through December] YYYY; ' - u'DD [January through December], YYYY']}) + self.assertEquals(serializer.errors, {'date': ['Date has wrong format. Use one of these formats instead: ' + 'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' + '[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' + 'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' + '[January through December] DD, YYYY; DD [January through December] YYYY; ' + 'DD [January through December], YYYY']}) def test_wrong_custom_date_input_format(self): serializer = DateObjectCustomFormatSerializer(data={'date': '07/31/1984'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date': [u'Date has wrong format. Use one of these formats instead: YYYY; YYYY -- MM']}) + self.assertEquals(serializer.errors, {'date': ['Date has wrong format. Use one of these formats instead: YYYY; YYYY -- MM']}) def test_from_native(self): f = serializers.DateField() @@ -223,12 +223,12 @@ class DateFieldTest(TestCase): try: f.from_native('1984-42-31') except validators.ValidationError as e: - self.assertEqual(e.messages, [u'Date has wrong format. Use one of these formats instead: ' - u'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' - u'[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' - u'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' - u'[January through December] DD, YYYY; DD [January through December] YYYY; ' - u'DD [January through December], YYYY']) + self.assertEqual(e.messages, ['Date has wrong format. Use one of these formats instead: ' + 'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' + '[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' + 'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' + '[January through December] DD, YYYY; DD [January through December] YYYY; ' + 'DD [January through December], YYYY']) else: self.fail("ValidationError was not properly raised") @@ -284,25 +284,25 @@ class DateTimeFieldTest(TestCase): def test_wrong_default_date_time_input_format_for_django_gte_1_4(self): serializer = DateTimeObjectSerializer(data={'date_time': 'something wrong'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date_time': [u'Datetime has wrong format. Use one of these formats instead: ' - u'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' - u'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' - u'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' - u'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']}) + self.assertEquals(serializer.errors, {'date_time': ['Datetime has wrong format. Use one of these formats instead: ' + 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' + 'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' + 'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' + 'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']}) @unittest.skipUnless(django.VERSION < (1, 4), "django >= 1.4 have microseconds in default settings") def test_wrong_default_date_time_input_format_for_django_lt_1_4(self): serializer = DateTimeObjectSerializer(data={'date_time': 'something wrong'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date_time': [u'Datetime has wrong format. Use one of these formats instead:' - u' YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' - u'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' - u'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']}) + self.assertEquals(serializer.errors, {'date_time': ['Datetime has wrong format. Use one of these formats instead: ' + 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' + 'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' + 'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']}) def test_wrong_custom_date_time_input_format(self): serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '07/31/84 04:31'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date_time': [u'Datetime has wrong format. Use one of these formats instead: YYYY; YYYY HH:MM']}) + self.assertEquals(serializer.errors, {'date_time': ['Datetime has wrong format. Use one of these formats instead: YYYY; YYYY HH:MM']}) def test_from_native(self): f = serializers.DateTimeField() @@ -326,31 +326,31 @@ class DateTimeFieldTest(TestCase): self.assertEqual(result, None) @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") - def test_from_native_invalid_datetime(self): + def test_from_native_invalid_datetime_for_django_gte_1_4(self): f = serializers.DateTimeField() try: f.from_native('1984-42-31 04:31') except validators.ValidationError as e: - self.assertEqual(e.messages, [u'Datetime has wrong format. Use one of these formats instead: ' - u'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' - u'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' - u'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' - u'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']) + self.assertEqual(e.messages, ['Datetime has wrong format. Use one of these formats instead: ' + 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' + 'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' + 'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' + 'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']) else: self.fail("ValidationError was not properly raised") @unittest.skipUnless(django.VERSION < (1, 4), "django >= 1.4 have microseconds in default settings") - def test_from_native_invalid_datetime(self): + def test_from_native_invalid_datetime_for_django_lt_1_4(self): f = serializers.DateTimeField() try: f.from_native('1984-42-31 04:31') except validators.ValidationError as e: - self.assertEqual(e.messages, [u'Datetime has wrong format. Use one of these formats instead:' - u' YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' - u'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' - u'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']) + self.assertEqual(e.messages, ['Datetime has wrong format. Use one of these formats instead: ' + 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' + 'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' + 'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']) else: self.fail("ValidationError was not properly raised") @@ -373,12 +373,12 @@ class TimeFieldTest(TestCase): def test_wrong_default_time_input_format(self): serializer = TimeObjectSerializer(data={'time': 'something wrong'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'time': [u'Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM']}) + self.assertEquals(serializer.errors, {'time': ['Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM']}) def test_wrong_custom_time_input_format(self): serializer = TimeObjectCustomFormatSerializer(data={'time': '04:31'}) self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'time': [u'Time has wrong format. Use one of these formats instead: HH -- MM; HHMMSS']}) + self.assertEquals(serializer.errors, {'time': ['Time has wrong format. Use one of these formats instead: HH -- MM; HHMMSS']}) def test_from_native(self): f = serializers.TimeField() -- cgit v1.2.3 From f208d8d2bbe2f418caa51199070f703fba544d49 Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Fri, 1 Mar 2013 13:16:00 +0100 Subject: Add drf settings + output format + testcases --- rest_framework/fields.py | 40 ++- rest_framework/settings.py | 21 ++ rest_framework/tests/fields.py | 503 ++++++++++++++++++------------------- rest_framework/tests/filterset.py | 13 +- rest_framework/tests/pagination.py | 4 +- rest_framework/tests/serializer.py | 2 +- 6 files changed, 310 insertions(+), 273 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index d38b726a..bb77164a 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -13,12 +13,12 @@ from django import forms from django.forms import widgets from django.utils.encoding import is_protected_type from django.utils.translation import ugettext_lazy as _ -from rest_framework.compat import parse_date, parse_datetime + from rest_framework.compat import timezone from rest_framework.compat import BytesIO from rest_framework.compat import six from rest_framework.compat import smart_text -from rest_framework.compat import parse_time +from rest_framework.settings import api_settings from rest_framework.utils.dates import get_readable_date_format @@ -453,7 +453,8 @@ class DateField(WritableField): empty = None def __init__(self, *args, **kwargs): - self.format = kwargs.pop('format', settings.DATE_INPUT_FORMATS) + self.input_formats = kwargs.pop('input_formats', api_settings.DATE_INPUT_FORMATS) + self.output_format = kwargs.pop('output_format', api_settings.DATE_OUTPUT_FORMAT) super(DateField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -470,7 +471,7 @@ class DateField(WritableField): if isinstance(value, datetime.date): return value - for format in self.format: + for format in self.input_formats: try: parsed = datetime.datetime.strptime(value, format) except (ValueError, TypeError): @@ -478,10 +479,15 @@ class DateField(WritableField): else: return parsed.date() - date_input_formats = '; '.join(self.format) + date_input_formats = '; '.join(self.input_formats) msg = self.error_messages['invalid'] % get_readable_date_format(date_input_formats) raise ValidationError(msg) + def to_native(self, value): + if self.output_format is not None: + return value.strftime(self.output_format) + return value.isoformat() + class DateTimeField(WritableField): type_name = 'DateTimeField' @@ -494,7 +500,8 @@ class DateTimeField(WritableField): empty = None def __init__(self, *args, **kwargs): - self.format = kwargs.pop('format', settings.DATETIME_INPUT_FORMATS) + self.input_formats = kwargs.pop('input_formats', api_settings.DATETIME_INPUT_FORMATS) + self.output_format = kwargs.pop('output_format', api_settings.DATETIME_OUTPUT_FORMAT) super(DateTimeField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -517,7 +524,7 @@ class DateTimeField(WritableField): value = timezone.make_aware(value, default_timezone) return value - for format in self.format: + for format in self.input_formats: try: parsed = datetime.datetime.strptime(value, format) except (ValueError, TypeError): @@ -525,10 +532,15 @@ class DateTimeField(WritableField): else: return parsed - datetime_input_formats = '; '.join(self.format) + datetime_input_formats = '; '.join(self.input_formats) msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats) raise ValidationError(msg) + def to_native(self, value): + if self.output_format is not None: + return value.strftime(self.output_format) + return value.isoformat() + class TimeField(WritableField): type_name = 'TimeField' @@ -541,7 +553,8 @@ class TimeField(WritableField): empty = None def __init__(self, *args, **kwargs): - self.format = kwargs.pop('format', settings.TIME_INPUT_FORMATS) + self.input_formats = kwargs.pop('input_formats', api_settings.TIME_INPUT_FORMATS) + self.output_format = kwargs.pop('output_format', api_settings.TIME_OUTPUT_FORMAT) super(TimeField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -551,7 +564,7 @@ class TimeField(WritableField): if isinstance(value, datetime.time): return value - for format in self.format: + for format in self.input_formats: try: parsed = datetime.datetime.strptime(value, format) except (ValueError, TypeError): @@ -559,10 +572,15 @@ class TimeField(WritableField): else: return parsed.time() - time_input_formats = '; '.join(self.format) + time_input_formats = '; '.join(self.input_formats) msg = self.error_messages['invalid'] % get_readable_date_format(time_input_formats) raise ValidationError(msg) + def to_native(self, value): + if self.output_format is not None: + return value.strftime(self.output_format) + return value.isoformat() + class IntegerField(WritableField): type_name = 'IntegerField' diff --git a/rest_framework/settings.py b/rest_framework/settings.py index b7aa0bbe..717496ea 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -76,6 +76,27 @@ DEFAULTS = { 'URL_FORMAT_OVERRIDE': 'format', 'FORMAT_SUFFIX_KWARG': 'format', + + # Input and output formats + 'DATE_INPUT_FORMATS': ( + '%Y-%m-%d', # '1984-07-31' + ), + 'DATE_OUTPUT_FORMAT': None, + + 'DATETIME_INPUT_FORMATS': ( + '%Y-%m-%d', # '1984-07-31' + '%Y-%m-%d %H:%M', # '1984-07-31 04:31' + '%Y-%m-%d %H:%M:%S', # '1984-07-31 04:31:59' + '%Y-%m-%d %H:%M:%S.%f', # '1984-07-31 04:31:59.000200' + ), + 'DATETIME_OUTPUT_FORMAT': None, + + 'TIME_INPUT_FORMATS': ( + '%H:%M', # '04:31' + '%H:%M:%S', # '04:31:59' + '%H:%M:%S.%f', # '04:31:59.000200' + ), + 'TIME_OUTPUT_FORMAT': None, } diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index a3429096..6630e0b2 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -4,11 +4,9 @@ General serializer field tests. from __future__ import unicode_literals import datetime -import django from django.db import models from django.test import TestCase from django.core import validators -from django.utils import unittest from rest_framework import serializers @@ -22,21 +20,6 @@ class CharPrimaryKeyModel(models.Model): id = models.CharField(max_length=20, primary_key=True) -class DateObject(object): - def __init__(self, date): - self.date = date - - -class DateTimeObject(object): - def __init__(self, date_time): - self.date_time = date_time - - -class TimeObject(object): - def __init__(self, time): - self.time = time - - class TimestampedModelSerializer(serializers.ModelSerializer): class Meta: model = TimestampedModel @@ -47,66 +30,6 @@ class CharPrimaryKeyModelSerializer(serializers.ModelSerializer): model = CharPrimaryKeyModel -class DateObjectSerializer(serializers.Serializer): - date = serializers.DateField() - - def restore_object(self, attrs, instance=None): - if instance is not None: - instance.date = attrs['date'] - return instance - return DateObject(**attrs) - - -class DateObjectCustomFormatSerializer(serializers.Serializer): - date = serializers.DateField(format=("%Y", "%Y -- %m")) - - def restore_object(self, attrs, instance=None): - if instance is not None: - instance.date = attrs['date'] - return instance - return DateObject(**attrs) - - -class DateTimeObjectSerializer(serializers.Serializer): - date_time = serializers.DateTimeField() - - def restore_object(self, attrs, instance=None): - if instance is not None: - instance.date_time = attrs['date_time'] - return instance - return DateTimeObject(**attrs) - - -class DateTimeObjectCustomFormatSerializer(serializers.Serializer): - date_time = serializers.DateTimeField(format=("%Y", "%Y %H:%M")) - - def restore_object(self, attrs, instance=None): - if instance is not None: - instance.date_time = attrs['date_time'] - return instance - return DateTimeObject(**attrs) - - -class TimeObjectSerializer(serializers.Serializer): - time = serializers.TimeField() - - def restore_object(self, attrs, instance=None): - if instance is not None: - instance.time = attrs['time'] - return instance - return TimeObject(**attrs) - - -class TimeObjectCustomFormatSerializer(serializers.Serializer): - time = serializers.TimeField(format=("%H -- %M", "%H%M%S")) - - def restore_object(self, attrs, instance=None): - if instance is not None: - instance.time = attrs['time'] - return instance - return TimeObject(**attrs) - - class TimeFieldModel(models.Model): clock = models.TimeField() @@ -136,277 +59,351 @@ class BasicFieldTests(TestCase): PK fields other than AutoField fields should not be read_only by default. """ serializer = CharPrimaryKeyModelSerializer() - self.assertEqual(serializer.fields['id'].read_only, False) + self.assertEquals(serializer.fields['id'].read_only, False) class DateFieldTest(TestCase): - def test_valid_default_date_input_formats(self): - serializer = DateObjectSerializer(data={'date': '1984-07-31'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': '07/31/1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': '07/31/84'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': 'Jul 31 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': 'Jul 31, 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': '31 Jul 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': '31 Jul 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': 'July 31 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': 'July 31, 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': '31 July 1984'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateObjectSerializer(data={'date': '31 July, 1984'}) - self.assertTrue(serializer.is_valid()) - - def test_valid_custom_date_input_formats(self): - serializer = DateObjectCustomFormatSerializer(data={'date': '1984'}) - self.assertTrue(serializer.is_valid()) + """ + Tests for the DateFieldTest from_native() and to_native() behavior + """ - serializer = DateObjectCustomFormatSerializer(data={'date': '1984 -- 07'}) - self.assertTrue(serializer.is_valid()) - - def test_wrong_default_date_input_format(self): - serializer = DateObjectSerializer(data={'date': 'something wrong'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date': ['Date has wrong format. Use one of these formats instead: ' - 'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' - '[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' - 'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' - '[January through December] DD, YYYY; DD [January through December] YYYY; ' - 'DD [January through December], YYYY']}) - - def test_wrong_custom_date_input_format(self): - serializer = DateObjectCustomFormatSerializer(data={'date': '07/31/1984'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date': ['Date has wrong format. Use one of these formats instead: YYYY; YYYY -- MM']}) - - def test_from_native(self): + def test_from_native_string(self): + """ + Make sure from_native() accepts default iso input formats. + """ f = serializers.DateField() - result = f.from_native('1984-07-31') + result_1 = f.from_native('1984-07-31') - self.assertEqual(datetime.date(1984, 7, 31), result) + self.assertEqual(datetime.date(1984, 7, 31), result_1) def test_from_native_datetime_date(self): """ Make sure from_native() accepts a datetime.date instance. """ f = serializers.DateField() - result = f.from_native(datetime.date(1984, 7, 31)) + result_1 = f.from_native(datetime.date(1984, 7, 31)) + + self.assertEqual(result_1, datetime.date(1984, 7, 31)) + + def test_from_native_custom_format(self): + """ + Make sure from_native() accepts custom input formats. + """ + f = serializers.DateField(input_formats=['%Y -- %d']) + result = f.from_native('1984 -- 31') - self.assertEqual(result, datetime.date(1984, 7, 31)) + self.assertEqual(datetime.date(1984, 1, 31), result) + + def test_from_native_invalid_default_on_custom_format(self): + """ + Make sure from_native() don't accept default formats if custom format is preset + """ + f = serializers.DateField(input_formats=['%Y -- %d']) + + try: + f.from_native('1984-07-31') + except validators.ValidationError as e: + self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY -- DD"]) + else: + self.fail("ValidationError was not properly raised") def test_from_native_empty(self): + """ + Make sure from_native() returns None on empty param. + """ f = serializers.DateField() result = f.from_native('') self.assertEqual(result, None) def test_from_native_invalid_date(self): + """ + Make sure from_native() raises a ValidationError on passing an invalid date. + """ f = serializers.DateField() try: - f.from_native('1984-42-31') + f.from_native('1984-13-31') except validators.ValidationError as e: - self.assertEqual(e.messages, ['Date has wrong format. Use one of these formats instead: ' - 'YYYY-MM-DD; MM/DD/YYYY; MM/DD/YY; [Jan through Dec] DD YYYY; ' - '[Jan through Dec] DD, YYYY; DD [Jan through Dec] YYYY; ' - 'DD [Jan through Dec], YYYY; [January through December] DD YYYY; ' - '[January through December] DD, YYYY; DD [January through December] YYYY; ' - 'DD [January through December], YYYY']) + self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY-MM-DD"]) else: self.fail("ValidationError was not properly raised") + def test_from_native_invalid_format(self): + """ + Make sure from_native() raises a ValidationError on passing an invalid format. + """ + f = serializers.DateField() -class DateTimeFieldTest(TestCase): - def test_valid_default_date_time_input_formats(self): - serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31 04:31:59'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31 04:31'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984 04:31:59'}) - self.assertTrue(serializer.is_valid()) - - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984 04:31'}) - self.assertTrue(serializer.is_valid()) + try: + f.from_native('1984 -- 31') + except validators.ValidationError as e: + self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY-MM-DD"]) + else: + self.fail("ValidationError was not properly raised") - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984'}) - self.assertTrue(serializer.is_valid()) + def test_to_native(self): + """ + Make sure to_native() returns isoformat as default. + """ + f = serializers.DateField() - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84 04:31:59'}) - self.assertTrue(serializer.is_valid()) + result_1 = f.to_native(datetime.date(1984, 7, 31)) - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84 04:31'}) - self.assertTrue(serializer.is_valid()) + self.assertEqual('1984-07-31', result_1) - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84'}) - self.assertTrue(serializer.is_valid()) + def test_to_native_custom_format(self): + """ + Make sure to_native() returns correct custom format. + """ + f = serializers.DateField(output_format="%Y - %m.%d") - @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") - def test_valid_default_date_time_input_formats_for_django_gte_1_4(self): - serializer = DateTimeObjectSerializer(data={'date_time': '1984-07-31 04:31:59.123456'}) - self.assertTrue(serializer.is_valid()) + result_1 = f.to_native(datetime.date(1984, 7, 31)) - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/1984 04:31:59.123456'}) - self.assertTrue(serializer.is_valid()) + self.assertEqual('1984 - 07.31', result_1) - serializer = DateTimeObjectSerializer(data={'date_time': '07/31/84 04:31:59.123456'}) - self.assertTrue(serializer.is_valid()) - def test_valid_custom_date_time_input_formats(self): - serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '1984'}) - self.assertTrue(serializer.is_valid()) +class DateTimeFieldTest(TestCase): + """ + Tests for the DateTimeField from_native() and to_native() behavior + """ - serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '1984 04:31'}) - self.assertTrue(serializer.is_valid()) + def test_from_native_string(self): + """ + Make sure from_native() accepts default iso input formats. + """ + f = serializers.DateTimeField() + result_1 = f.from_native('1984-07-31') + result_2 = f.from_native('1984-07-31 04:31') + result_3 = f.from_native('1984-07-31 04:31:59') + result_4 = f.from_native('1984-07-31 04:31:59.000200') - @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") - def test_wrong_default_date_time_input_format_for_django_gte_1_4(self): - serializer = DateTimeObjectSerializer(data={'date_time': 'something wrong'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date_time': ['Datetime has wrong format. Use one of these formats instead: ' - 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' - 'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' - 'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' - 'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']}) + self.assertEqual(datetime.datetime(1984, 7, 31), result_1) + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_2) + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_3) + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_4) - @unittest.skipUnless(django.VERSION < (1, 4), "django >= 1.4 have microseconds in default settings") - def test_wrong_default_date_time_input_format_for_django_lt_1_4(self): - serializer = DateTimeObjectSerializer(data={'date_time': 'something wrong'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date_time': ['Datetime has wrong format. Use one of these formats instead: ' - 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' - 'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' - 'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']}) + def test_from_native_datetime_datetime(self): + """ + Make sure from_native() accepts a datetime.datetime instance. + """ + f = serializers.DateTimeField() + result_1 = f.from_native(datetime.datetime(1984, 7, 31)) + result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31)) + result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59)) + result_4 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) - def test_wrong_custom_date_time_input_format(self): - serializer = DateTimeObjectCustomFormatSerializer(data={'date_time': '07/31/84 04:31'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'date_time': ['Datetime has wrong format. Use one of these formats instead: YYYY; YYYY HH:MM']}) + self.assertEqual(result_1, datetime.datetime(1984, 7, 31)) + self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31)) + self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59)) + self.assertEqual(result_4, datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) - def test_from_native(self): - f = serializers.DateTimeField() - result = f.from_native('1984-07-31 04:31') + def test_from_native_custom_format(self): + """ + Make sure from_native() accepts custom input formats. + """ + f = serializers.DateTimeField(input_formats=['%Y -- %H:%M']) + result = f.from_native('1984 -- 04:59') - self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result) + self.assertEqual(datetime.datetime(1984, 1, 1, 4, 59), result) - def test_from_native_datetime_datetime(self): + def test_from_native_invalid_default_on_custom_format(self): """ - Make sure from_native() accepts a datetime.date instance. + Make sure from_native() don't accept default formats if custom format is preset """ - f = serializers.DateTimeField() - result = f.from_native(datetime.datetime(1984, 7, 31)) + f = serializers.DateTimeField(input_formats=['%Y -- %H:%M']) - self.assertEqual(result, datetime.datetime(1984, 7, 31)) + try: + f.from_native('1984-07-31 04:31:59') + except validators.ValidationError as e: + self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: YYYY -- HH:MM"]) + else: + self.fail("ValidationError was not properly raised") def test_from_native_empty(self): + """ + Make sure from_native() returns None on empty param. + """ f = serializers.DateTimeField() result = f.from_native('') self.assertEqual(result, None) - @unittest.skipUnless(django.VERSION >= (1, 4), "django < 1.4 don't have microseconds in default settings") - def test_from_native_invalid_datetime_for_django_gte_1_4(self): + def test_from_native_invalid_datetime(self): + """ + Make sure from_native() raises a ValidationError on passing an invalid datetime. + """ f = serializers.DateTimeField() try: - f.from_native('1984-42-31 04:31') + f.from_native('04:61:59') except validators.ValidationError as e: - self.assertEqual(e.messages, ['Datetime has wrong format. Use one of these formats instead: ' - 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM:SS.uuuuuu; YYYY-MM-DD HH:MM; ' - 'YYYY-MM-DD; MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM:SS.uuuuuu; ' - 'MM/DD/YYYY HH:MM; MM/DD/YYYY; MM/DD/YY HH:MM:SS; ' - 'MM/DD/YY HH:MM:SS.uuuuuu; MM/DD/YY HH:MM; MM/DD/YY']) + self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " + "YYYY-MM-DD; YYYY-MM-DD HH:MM; YYYY-MM-DD HH:MM:SS; " + "YYYY-MM-DD HH:MM:SS.uuuuuu"]) else: self.fail("ValidationError was not properly raised") - @unittest.skipUnless(django.VERSION < (1, 4), "django >= 1.4 have microseconds in default settings") - def test_from_native_invalid_datetime_for_django_lt_1_4(self): + def test_from_native_invalid_format(self): + """ + Make sure from_native() raises a ValidationError on passing an invalid format. + """ f = serializers.DateTimeField() try: - f.from_native('1984-42-31 04:31') + f.from_native('04 -- 31') except validators.ValidationError as e: - self.assertEqual(e.messages, ['Datetime has wrong format. Use one of these formats instead: ' - 'YYYY-MM-DD HH:MM:SS; YYYY-MM-DD HH:MM; YYYY-MM-DD; ' - 'MM/DD/YYYY HH:MM:SS; MM/DD/YYYY HH:MM; MM/DD/YYYY; ' - 'MM/DD/YY HH:MM:SS; MM/DD/YY HH:MM; MM/DD/YY']) + self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " + "YYYY-MM-DD; YYYY-MM-DD HH:MM; YYYY-MM-DD HH:MM:SS; " + "YYYY-MM-DD HH:MM:SS.uuuuuu"]) else: self.fail("ValidationError was not properly raised") + def test_to_native(self): + """ + Make sure to_native() returns isoformat as default. + """ + f = serializers.DateTimeField() -class TimeFieldTest(TestCase): - def test_valid_default_time_input_formats(self): - serializer = TimeObjectSerializer(data={'time': '04:31'}) - self.assertTrue(serializer.is_valid()) + result_1 = f.to_native(datetime.datetime(1984, 7, 31)) + result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31)) + result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59)) + result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) - serializer = TimeObjectSerializer(data={'time': '04:31:59'}) - self.assertTrue(serializer.is_valid()) + self.assertEqual('1984-07-31T00:00:00', result_1) + self.assertEqual('1984-07-31T04:31:00', result_2) + self.assertEqual('1984-07-31T04:31:59', result_3) + self.assertEqual('1984-07-31T04:31:59.000200', result_4) - def test_valid_custom_time_input_formats(self): - serializer = TimeObjectCustomFormatSerializer(data={'time': '04 -- 31'}) - self.assertTrue(serializer.is_valid()) + def test_to_native_custom_format(self): + """ + Make sure to_native() returns correct custom format. + """ + f = serializers.DateTimeField(output_format="%Y - %H:%M") - serializer = TimeObjectCustomFormatSerializer(data={'time': '043159'}) - self.assertTrue(serializer.is_valid()) + result_1 = f.to_native(datetime.datetime(1984, 7, 31)) + result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31)) + result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59)) + result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) - def test_wrong_default_time_input_format(self): - serializer = TimeObjectSerializer(data={'time': 'something wrong'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'time': ['Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM']}) + self.assertEqual('1984 - 00:00', result_1) + self.assertEqual('1984 - 04:31', result_2) + self.assertEqual('1984 - 04:31', result_3) + self.assertEqual('1984 - 04:31', result_4) - def test_wrong_custom_time_input_format(self): - serializer = TimeObjectCustomFormatSerializer(data={'time': '04:31'}) - self.assertFalse(serializer.is_valid()) - self.assertEquals(serializer.errors, {'time': ['Time has wrong format. Use one of these formats instead: HH -- MM; HHMMSS']}) - def test_from_native(self): +class TimeFieldTest(TestCase): + """ + Tests for the TimeField from_native() and to_native() behavior + """ + + def test_from_native_string(self): + """ + Make sure from_native() accepts default iso input formats. + """ f = serializers.TimeField() - result = f.from_native('12:34:56') + result_1 = f.from_native('04:31') + result_2 = f.from_native('04:31:59') + result_3 = f.from_native('04:31:59.000200') - self.assertEqual(datetime.time(12, 34, 56), result) + self.assertEqual(datetime.time(4, 31), result_1) + self.assertEqual(datetime.time(4, 31, 59), result_2) + self.assertEqual(datetime.time(4, 31, 59, 200), result_3) def test_from_native_datetime_time(self): """ Make sure from_native() accepts a datetime.time instance. """ f = serializers.TimeField() - result = f.from_native(datetime.time(12, 34, 56)) + result_1 = f.from_native(datetime.time(4, 31)) + result_2 = f.from_native(datetime.time(4, 31, 59)) + result_3 = f.from_native(datetime.time(4, 31, 59, 200)) + + self.assertEqual(result_1, datetime.time(4, 31)) + self.assertEqual(result_2, datetime.time(4, 31, 59)) + self.assertEqual(result_3, datetime.time(4, 31, 59, 200)) + + def test_from_native_custom_format(self): + """ + Make sure from_native() accepts custom input formats. + """ + f = serializers.TimeField(input_formats=['%H -- %M']) + result = f.from_native('04 -- 31') + + self.assertEqual(datetime.time(4, 31), result) + + def test_from_native_invalid_default_on_custom_format(self): + """ + Make sure from_native() don't accept default formats if custom format is preset + """ + f = serializers.TimeField(input_formats=['%H -- %M']) - self.assertEqual(result, datetime.time(12, 34, 56)) + try: + f.from_native('04:31:59') + except validators.ValidationError as e: + self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: HH -- MM"]) + else: + self.fail("ValidationError was not properly raised") def test_from_native_empty(self): + """ + Make sure from_native() returns None on empty param. + """ f = serializers.TimeField() result = f.from_native('') self.assertEqual(result, None) def test_from_native_invalid_time(self): + """ + Make sure from_native() raises a ValidationError on passing an invalid time. + """ f = serializers.TimeField() try: - f.from_native('12:69:12') + f.from_native('04:61:59') except validators.ValidationError as e: - self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM"]) + self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " + "HH:MM; HH:MM:SS; HH:MM:SS.uuuuuu"]) else: self.fail("ValidationError was not properly raised") + + def test_from_native_invalid_format(self): + """ + Make sure from_native() raises a ValidationError on passing an invalid format. + """ + f = serializers.TimeField() + + try: + f.from_native('04 -- 31') + except validators.ValidationError as e: + self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " + "HH:MM; HH:MM:SS; HH:MM:SS.uuuuuu"]) + else: + self.fail("ValidationError was not properly raised") + + def test_to_native(self): + """ + Make sure to_native() returns isoformat as default. + """ + f = serializers.TimeField() + result_1 = f.to_native(datetime.time(4, 31)) + result_2 = f.to_native(datetime.time(4, 31, 59)) + result_3 = f.to_native(datetime.time(4, 31, 59, 200)) + + self.assertEqual('04:31:00', result_1) + self.assertEqual('04:31:59', result_2) + self.assertEqual('04:31:59.000200', result_3) + + def test_to_native_custom_format(self): + """ + Make sure to_native() returns correct custom format. + """ + f = serializers.TimeField(output_format="%H - %S [%f]") + result_1 = f.to_native(datetime.time(4, 31)) + result_2 = f.to_native(datetime.time(4, 31, 59)) + result_3 = f.to_native(datetime.time(4, 31, 59, 200)) + + self.assertEqual('04 - 00 [000000]', result_1) + self.assertEqual('04 - 59 [000000]', result_2) + self.assertEqual('04 - 59 [000200]', result_3) \ No newline at end of file diff --git a/rest_framework/tests/filterset.py b/rest_framework/tests/filterset.py index 8c13947c..fe92e0bc 100644 --- a/rest_framework/tests/filterset.py +++ b/rest_framework/tests/filterset.py @@ -65,8 +65,8 @@ class IntegrationTestFiltering(TestCase): self.objects = FilterableItem.objects self.data = [ - {'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date} - for obj in self.objects.all() + {'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()} + for obj in self.objects.all() ] @unittest.skipUnless(django_filters, 'django-filters not installed') @@ -95,7 +95,7 @@ class IntegrationTestFiltering(TestCase): request = factory.get('/?date=%s' % search_date) # search_date str: '2012-09-22' response = view(request).render() self.assertEqual(response.status_code, status.HTTP_200_OK) - expected_data = [f for f in self.data if f['date'] == search_date] + expected_data = [f for f in self.data if datetime.datetime.strptime(f['date'], '%Y-%m-%d').date() == search_date] self.assertEqual(response.data, expected_data) @unittest.skipUnless(django_filters, 'django-filters not installed') @@ -125,7 +125,7 @@ class IntegrationTestFiltering(TestCase): request = factory.get('/?date=%s' % search_date) # search_date str: '2012-10-02' response = view(request).render() self.assertEqual(response.status_code, status.HTTP_200_OK) - expected_data = [f for f in self.data if f['date'] > search_date] + expected_data = [f for f in self.data if datetime.datetime.strptime(f['date'], '%Y-%m-%d').date() > search_date] self.assertEqual(response.data, expected_data) # Tests that the text filter set with 'icontains' in the filter class works. @@ -142,8 +142,9 @@ class IntegrationTestFiltering(TestCase): request = factory.get('/?decimal=%s&date=%s' % (search_decimal, search_date)) response = view(request).render() self.assertEqual(response.status_code, status.HTTP_200_OK) - expected_data = [f for f in self.data if f['date'] > search_date and - f['decimal'] < search_decimal] + expected_data = [f for f in self.data if + datetime.datetime.strptime(f['date'], '%Y-%m-%d').date() > search_date and + f['decimal'] < search_decimal] self.assertEqual(response.data, expected_data) @unittest.skipUnless(django_filters, 'django-filters not installed') diff --git a/rest_framework/tests/pagination.py b/rest_framework/tests/pagination.py index 6b9970a6..472ffcdd 100644 --- a/rest_framework/tests/pagination.py +++ b/rest_framework/tests/pagination.py @@ -112,8 +112,8 @@ class IntegrationTestPaginationAndFiltering(TestCase): self.objects = FilterableItem.objects self.data = [ - {'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date} - for obj in self.objects.all() + {'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()} + for obj in self.objects.all() ] self.view = FilterFieldsRootView.as_view() diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index d0300f9e..51065017 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -112,7 +112,7 @@ class BasicTests(TestCase): self.expected = { 'email': 'tom@example.com', 'content': 'Happy new year!', - 'created': datetime.datetime(2012, 1, 1), + 'created': '2012-01-01T00:00:00', 'sub_comment': 'And Merry Christmas!' } self.person_data = {'name': 'dwight', 'age': 35} -- cgit v1.2.3 From a9d36d4726fc8eea02184b089ee6ed1d02e4c75e Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Fri, 1 Mar 2013 15:03:27 +0100 Subject: Add docs update - part 1 --- rest_framework/fields.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index bb77164a..3eaa532a 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -452,9 +452,9 @@ class DateField(WritableField): } empty = None - def __init__(self, *args, **kwargs): - self.input_formats = kwargs.pop('input_formats', api_settings.DATE_INPUT_FORMATS) - self.output_format = kwargs.pop('output_format', api_settings.DATE_OUTPUT_FORMAT) + def __init__(self, input_formats=None, output_format=None, *args, **kwargs): + self.input_formats = input_formats or api_settings.DATE_INPUT_FORMATS + self.output_format = output_format or api_settings.DATE_OUTPUT_FORMAT super(DateField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -499,9 +499,9 @@ class DateTimeField(WritableField): } empty = None - def __init__(self, *args, **kwargs): - self.input_formats = kwargs.pop('input_formats', api_settings.DATETIME_INPUT_FORMATS) - self.output_format = kwargs.pop('output_format', api_settings.DATETIME_OUTPUT_FORMAT) + def __init__(self, input_formats=None, output_format=None, *args, **kwargs): + self.input_formats = input_formats or api_settings.DATETIME_INPUT_FORMATS + self.output_format = output_format or api_settings.DATETIME_OUTPUT_FORMAT super(DateTimeField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -552,9 +552,9 @@ class TimeField(WritableField): } empty = None - def __init__(self, *args, **kwargs): - self.input_formats = kwargs.pop('input_formats', api_settings.TIME_INPUT_FORMATS) - self.output_format = kwargs.pop('output_format', api_settings.TIME_OUTPUT_FORMAT) + def __init__(self, input_formats=None, output_format=None, *args, **kwargs): + self.input_formats = input_formats or api_settings.TIME_INPUT_FORMATS + self.output_format = output_format or api_settings.TIME_OUTPUT_FORMAT super(TimeField, self).__init__(*args, **kwargs) def from_native(self, value): -- cgit v1.2.3 From 9c964cf37b6936e907d250306e15c3f116591e7c Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Fri, 1 Mar 2013 16:24:25 +0100 Subject: Add new ISO8601 setting + integration --- rest_framework/__init__.py | 3 ++ rest_framework/fields.py | 83 ++++++++++++++++++++++++++++-------------- rest_framework/settings.py | 20 +++++----- rest_framework/tests/fields.py | 38 ++++++++----------- 4 files changed, 84 insertions(+), 60 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index 29f3d7bc..d26bb6bf 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -4,3 +4,6 @@ VERSION = __version__ # synonym # Header encoding (see RFC5987) HTTP_HEADER_ENCODING = 'iso-8859-1' + +# Default input and output format +ISO8601 = 'iso-8601' \ No newline at end of file diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 3eaa532a..c3e83c5e 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -11,9 +11,11 @@ from django.core.exceptions import ValidationError from django.conf import settings from django import forms from django.forms import widgets +from django.utils.dateparse import parse_date, parse_datetime, parse_time from django.utils.encoding import is_protected_type from django.utils.translation import ugettext_lazy as _ +from rest_framework import ISO8601 from rest_framework.compat import timezone from rest_framework.compat import BytesIO from rest_framework.compat import six @@ -472,21 +474,30 @@ class DateField(WritableField): return value for format in self.input_formats: - try: - parsed = datetime.datetime.strptime(value, format) - except (ValueError, TypeError): - pass + if format.lower() == ISO8601: + try: + parsed = parse_date(value) + except (ValueError, TypeError): + pass + else: + if parsed is not None: + return parsed else: - return parsed.date() + try: + parsed = datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + pass + else: + return parsed.date() - date_input_formats = '; '.join(self.input_formats) + date_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'YYYY-MM-DD') msg = self.error_messages['invalid'] % get_readable_date_format(date_input_formats) raise ValidationError(msg) def to_native(self, value): - if self.output_format is not None: - return value.strftime(self.output_format) - return value.isoformat() + if self.output_format.lower() == ISO8601: + return value.isoformat() + return value.strftime(self.output_format) class DateTimeField(WritableField): @@ -525,21 +536,30 @@ class DateTimeField(WritableField): return value for format in self.input_formats: - try: - parsed = datetime.datetime.strptime(value, format) - except (ValueError, TypeError): - pass + if format.lower() == ISO8601: + try: + parsed = parse_datetime(value) + except (ValueError, TypeError): + pass + else: + if parsed is not None: + return parsed else: - return parsed + try: + parsed = datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + pass + else: + return parsed - datetime_input_formats = '; '.join(self.input_formats) + datetime_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]') msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats) raise ValidationError(msg) def to_native(self, value): - if self.output_format is not None: - return value.strftime(self.output_format) - return value.isoformat() + if self.output_format.lower() == ISO8601: + return value.isoformat() + return value.strftime(self.output_format) class TimeField(WritableField): @@ -565,21 +585,30 @@ class TimeField(WritableField): return value for format in self.input_formats: - try: - parsed = datetime.datetime.strptime(value, format) - except (ValueError, TypeError): - pass + if format.lower() == ISO8601: + try: + parsed = parse_time(value) + except (ValueError, TypeError): + pass + else: + if parsed is not None: + return parsed else: - return parsed.time() + try: + parsed = datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + pass + else: + return parsed.time() - time_input_formats = '; '.join(self.input_formats) + time_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'HH:MM[:ss[.uuuuuu]]') msg = self.error_messages['invalid'] % get_readable_date_format(time_input_formats) raise ValidationError(msg) def to_native(self, value): - if self.output_format is not None: - return value.strftime(self.output_format) - return value.isoformat() + if self.output_format.lower() == ISO8601: + return value.isoformat() + return value.strftime(self.output_format) class IntegerField(WritableField): diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 717496ea..02d751e1 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -18,8 +18,11 @@ REST framework settings, checking for user settings first, then falling back to the defaults. """ from __future__ import unicode_literals + from django.conf import settings from django.utils import importlib + +from rest_framework import ISO8601 from rest_framework.compat import six @@ -79,24 +82,19 @@ DEFAULTS = { # Input and output formats 'DATE_INPUT_FORMATS': ( - '%Y-%m-%d', # '1984-07-31' + ISO8601, ), - 'DATE_OUTPUT_FORMAT': None, + 'DATE_OUTPUT_FORMAT': ISO8601, 'DATETIME_INPUT_FORMATS': ( - '%Y-%m-%d', # '1984-07-31' - '%Y-%m-%d %H:%M', # '1984-07-31 04:31' - '%Y-%m-%d %H:%M:%S', # '1984-07-31 04:31:59' - '%Y-%m-%d %H:%M:%S.%f', # '1984-07-31 04:31:59.000200' + ISO8601, ), - 'DATETIME_OUTPUT_FORMAT': None, + 'DATETIME_OUTPUT_FORMAT': ISO8601, 'TIME_INPUT_FORMATS': ( - '%H:%M', # '04:31' - '%H:%M:%S', # '04:31:59' - '%H:%M:%S.%f', # '04:31:59.000200' + ISO8601, ), - 'TIME_OUTPUT_FORMAT': None, + 'TIME_OUTPUT_FORMAT': ISO8601, } diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index 6630e0b2..3b84ab1c 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -173,30 +173,26 @@ class DateTimeFieldTest(TestCase): Make sure from_native() accepts default iso input formats. """ f = serializers.DateTimeField() - result_1 = f.from_native('1984-07-31') - result_2 = f.from_native('1984-07-31 04:31') - result_3 = f.from_native('1984-07-31 04:31:59') - result_4 = f.from_native('1984-07-31 04:31:59.000200') + result_1 = f.from_native('1984-07-31 04:31') + result_2 = f.from_native('1984-07-31 04:31:59') + result_3 = f.from_native('1984-07-31 04:31:59.000200') - self.assertEqual(datetime.datetime(1984, 7, 31), result_1) - self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_2) - self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_3) - self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_4) + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_1) + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_2) + self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_3) def test_from_native_datetime_datetime(self): """ Make sure from_native() accepts a datetime.datetime instance. """ f = serializers.DateTimeField() - result_1 = f.from_native(datetime.datetime(1984, 7, 31)) - result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31)) - result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59)) - result_4 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) + result_1 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31)) + result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59)) + result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) - self.assertEqual(result_1, datetime.datetime(1984, 7, 31)) - self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31)) - self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59)) - self.assertEqual(result_4, datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) + self.assertEqual(result_1, datetime.datetime(1984, 7, 31, 4, 31)) + self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31, 59)) + self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59, 200)) def test_from_native_custom_format(self): """ @@ -239,8 +235,7 @@ class DateTimeFieldTest(TestCase): f.from_native('04:61:59') except validators.ValidationError as e: self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " - "YYYY-MM-DD; YYYY-MM-DD HH:MM; YYYY-MM-DD HH:MM:SS; " - "YYYY-MM-DD HH:MM:SS.uuuuuu"]) + "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"]) else: self.fail("ValidationError was not properly raised") @@ -254,8 +249,7 @@ class DateTimeFieldTest(TestCase): f.from_native('04 -- 31') except validators.ValidationError as e: self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " - "YYYY-MM-DD; YYYY-MM-DD HH:MM; YYYY-MM-DD HH:MM:SS; " - "YYYY-MM-DD HH:MM:SS.uuuuuu"]) + "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"]) else: self.fail("ValidationError was not properly raised") @@ -364,7 +358,7 @@ class TimeFieldTest(TestCase): f.from_native('04:61:59') except validators.ValidationError as e: self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " - "HH:MM; HH:MM:SS; HH:MM:SS.uuuuuu"]) + "HH:MM[:ss[.uuuuuu]]"]) else: self.fail("ValidationError was not properly raised") @@ -378,7 +372,7 @@ class TimeFieldTest(TestCase): f.from_native('04 -- 31') except validators.ValidationError as e: self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " - "HH:MM; HH:MM:SS; HH:MM:SS.uuuuuu"]) + "HH:MM[:ss[.uuuuuu]]"]) else: self.fail("ValidationError was not properly raised") -- cgit v1.2.3 From 12905449a5591cef2b2fc94d68cc273dc6df0463 Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Fri, 1 Mar 2013 16:59:47 +0100 Subject: Add format class attributes --- rest_framework/fields.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index c3e83c5e..21ab92ed 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -453,10 +453,12 @@ class DateField(WritableField): 'invalid': _("Date has wrong format. Use one of these formats instead: %s"), } empty = None + input_formats = api_settings.DATE_INPUT_FORMATS + output_format = api_settings.DATE_OUTPUT_FORMAT def __init__(self, input_formats=None, output_format=None, *args, **kwargs): - self.input_formats = input_formats or api_settings.DATE_INPUT_FORMATS - self.output_format = output_format or api_settings.DATE_OUTPUT_FORMAT + self.input_formats = input_formats if input_formats is not None else self.input_formats + self.output_format = output_format if output_format is not None else self.output_format super(DateField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -509,10 +511,12 @@ class DateTimeField(WritableField): 'invalid': _("Datetime has wrong format. Use one of these formats instead: %s"), } empty = None + input_formats = api_settings.DATETIME_INPUT_FORMATS + output_format = api_settings.DATETIME_OUTPUT_FORMAT def __init__(self, input_formats=None, output_format=None, *args, **kwargs): - self.input_formats = input_formats or api_settings.DATETIME_INPUT_FORMATS - self.output_format = output_format or api_settings.DATETIME_OUTPUT_FORMAT + self.input_formats = input_formats if input_formats is not None else self.input_formats + self.output_format = output_format if output_format is not None else self.output_format super(DateTimeField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -571,10 +575,12 @@ class TimeField(WritableField): 'invalid': _("Time has wrong format. Use one of these formats instead: %s"), } empty = None + input_formats = api_settings.TIME_INPUT_FORMATS + output_format = api_settings.TIME_OUTPUT_FORMAT def __init__(self, input_formats=None, output_format=None, *args, **kwargs): - self.input_formats = input_formats or api_settings.TIME_INPUT_FORMATS - self.output_format = output_format or api_settings.TIME_OUTPUT_FORMAT + self.input_formats = input_formats if input_formats is not None else self.input_formats + self.output_format = output_format if output_format is not None else self.output_format super(TimeField, self).__init__(*args, **kwargs) def from_native(self, value): -- cgit v1.2.3 From 681ad6f5370c88c15ccde3ecd61e735cde514e1a Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Fri, 1 Mar 2013 17:04:30 +0100 Subject: Add none testcases to date, datetime, time --- rest_framework/tests/fields.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'rest_framework') diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index 3b84ab1c..17ef2f2c 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -116,6 +116,15 @@ class DateFieldTest(TestCase): self.assertEqual(result, None) + def test_from_native_none(self): + """ + Make sure from_native() returns None on None param. + """ + f = serializers.DateField() + result = f.from_native(None) + + self.assertEqual(result, None) + def test_from_native_invalid_date(self): """ Make sure from_native() raises a ValidationError on passing an invalid date. @@ -225,6 +234,15 @@ class DateTimeFieldTest(TestCase): self.assertEqual(result, None) + def test_from_native_none(self): + """ + Make sure from_native() returns None on None param. + """ + f = serializers.DateTimeField() + result = f.from_native(None) + + self.assertEqual(result, None) + def test_from_native_invalid_datetime(self): """ Make sure from_native() raises a ValidationError on passing an invalid datetime. @@ -348,6 +366,15 @@ class TimeFieldTest(TestCase): self.assertEqual(result, None) + def test_from_native_none(self): + """ + Make sure from_native() returns None on None param. + """ + f = serializers.TimeField() + result = f.from_native(None) + + self.assertEqual(result, None) + def test_from_native_invalid_time(self): """ Make sure from_native() raises a ValidationError on passing an invalid time. -- cgit v1.2.3 From 5e5cd6f7f7357d68d5c10500ec0379e49d679202 Mon Sep 17 00:00:00 2001 From: Stephan Groß Date: Fri, 1 Mar 2013 17:15:39 +0100 Subject: Fix for django 1.3 compatibility --- rest_framework/fields.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 21ab92ed..87e0161f 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -11,12 +11,11 @@ from django.core.exceptions import ValidationError from django.conf import settings from django import forms from django.forms import widgets -from django.utils.dateparse import parse_date, parse_datetime, parse_time from django.utils.encoding import is_protected_type from django.utils.translation import ugettext_lazy as _ from rest_framework import ISO8601 -from rest_framework.compat import timezone +from rest_framework.compat import timezone, parse_date, parse_datetime, parse_time from rest_framework.compat import BytesIO from rest_framework.compat import six from rest_framework.compat import smart_text -- cgit v1.2.3 From 1106596c80218569a56ff5ea04d759e3d0c541dd Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 6 Mar 2013 12:19:39 +0000 Subject: Clean ups to datetime formatting --- rest_framework/__init__.py | 2 +- rest_framework/fields.py | 88 +++++++++++++++++++++++++++++------------- rest_framework/settings.py | 14 +++---- rest_framework/tests/fields.py | 26 ++++++------- rest_framework/utils/dates.py | 14 ------- 5 files changed, 83 insertions(+), 61 deletions(-) delete mode 100644 rest_framework/utils/dates.py (limited to 'rest_framework') diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index d26bb6bf..14ab7ff0 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -6,4 +6,4 @@ VERSION = __version__ # synonym HTTP_HEADER_ENCODING = 'iso-8859-1' # Default input and output format -ISO8601 = 'iso-8601' \ No newline at end of file +ISO_8601 = 'iso-8601' diff --git a/rest_framework/fields.py b/rest_framework/fields.py index e65f0307..fe555ee5 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -14,13 +14,12 @@ from django.forms import widgets from django.utils.encoding import is_protected_type from django.utils.translation import ugettext_lazy as _ -from rest_framework import ISO8601 +from rest_framework import ISO_8601 from rest_framework.compat import timezone, parse_date, parse_datetime, parse_time from rest_framework.compat import BytesIO from rest_framework.compat import six from rest_framework.compat import smart_text from rest_framework.settings import api_settings -from rest_framework.utils.dates import get_readable_date_format def is_simple_callable(obj): @@ -52,6 +51,46 @@ def get_component(obj, attr_name): return val +def readable_datetime_formats(formats): + format = ', '.join(formats).replace(ISO_8601, 'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HHMM|-HHMM|Z]') + return humanize_strptime(format) + + +def readable_date_formats(formats): + format = ', '.join(formats).replace(ISO_8601, 'YYYY[-MM[-DD]]') + return humanize_strptime(format) + + +def readable_time_formats(formats): + format = ', '.join(formats).replace(ISO_8601, 'hh:mm[:ss[.uuuuuu]]') + return humanize_strptime(format) + + +def humanize_strptime(format_string): + # Note that we're missing some of the locale specific mappings that + # don't really make sense. + mapping = { + "%Y": "YYYY", + "%y": "YY", + "%m": "MM", + "%b": "[Jan-Dec]", + "%B": "[January-December]", + "%d": "DD", + "%H": "hh", + "%I": "hh", # Requires '%p' to differentiate from '%H'. + "%M": "mm", + "%S": "ss", + "%f": "uuuuuu", + "%a": "[Mon-Sun]", + "%A": "[Monday-Sunday]", + "%p": "[AM|PM]", + "%z": "[+HHMM|-HHMM]" + } + for key, val in mapping.items(): + format_string = format_string.replace(key, val) + return format_string + + class Field(object): read_only = True creation_counter = 0 @@ -453,11 +492,11 @@ class DateField(WritableField): } empty = None input_formats = api_settings.DATE_INPUT_FORMATS - output_format = api_settings.DATE_OUTPUT_FORMAT + format = api_settings.DATE_FORMAT - def __init__(self, input_formats=None, output_format=None, *args, **kwargs): + def __init__(self, input_formats=None, format=None, *args, **kwargs): self.input_formats = input_formats if input_formats is not None else self.input_formats - self.output_format = output_format if output_format is not None else self.output_format + self.format = format if format is not None else self.format super(DateField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -475,7 +514,7 @@ class DateField(WritableField): return value for format in self.input_formats: - if format.lower() == ISO8601: + if format.lower() == ISO_8601: try: parsed = parse_date(value) except (ValueError, TypeError): @@ -491,16 +530,15 @@ class DateField(WritableField): else: return parsed.date() - date_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'YYYY-MM-DD') - msg = self.error_messages['invalid'] % get_readable_date_format(date_input_formats) + msg = self.error_messages['invalid'] % readable_date_formats(self.input_formats) raise ValidationError(msg) def to_native(self, value): if isinstance(value, datetime.datetime): value = value.date() - if self.output_format.lower() == ISO8601: + if self.format.lower() == ISO_8601: return value.isoformat() - return value.strftime(self.output_format) + return value.strftime(self.format) class DateTimeField(WritableField): @@ -513,11 +551,11 @@ class DateTimeField(WritableField): } empty = None input_formats = api_settings.DATETIME_INPUT_FORMATS - output_format = api_settings.DATETIME_OUTPUT_FORMAT + format = api_settings.DATETIME_FORMAT - def __init__(self, input_formats=None, output_format=None, *args, **kwargs): + def __init__(self, input_formats=None, format=None, *args, **kwargs): self.input_formats = input_formats if input_formats is not None else self.input_formats - self.output_format = output_format if output_format is not None else self.output_format + self.format = format if format is not None else self.format super(DateTimeField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -541,7 +579,7 @@ class DateTimeField(WritableField): return value for format in self.input_formats: - if format.lower() == ISO8601: + if format.lower() == ISO_8601: try: parsed = parse_datetime(value) except (ValueError, TypeError): @@ -557,14 +595,13 @@ class DateTimeField(WritableField): else: return parsed - datetime_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]') - msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats) + msg = self.error_messages['invalid'] % readable_datetime_formats(self.input_formats) raise ValidationError(msg) def to_native(self, value): - if self.output_format.lower() == ISO8601: + if self.format.lower() == ISO_8601: return value.isoformat() - return value.strftime(self.output_format) + return value.strftime(self.format) class TimeField(WritableField): @@ -577,11 +614,11 @@ class TimeField(WritableField): } empty = None input_formats = api_settings.TIME_INPUT_FORMATS - output_format = api_settings.TIME_OUTPUT_FORMAT + format = api_settings.TIME_FORMAT - def __init__(self, input_formats=None, output_format=None, *args, **kwargs): + def __init__(self, input_formats=None, format=None, *args, **kwargs): self.input_formats = input_formats if input_formats is not None else self.input_formats - self.output_format = output_format if output_format is not None else self.output_format + self.format = format if format is not None else self.format super(TimeField, self).__init__(*args, **kwargs) def from_native(self, value): @@ -592,7 +629,7 @@ class TimeField(WritableField): return value for format in self.input_formats: - if format.lower() == ISO8601: + if format.lower() == ISO_8601: try: parsed = parse_time(value) except (ValueError, TypeError): @@ -608,16 +645,15 @@ class TimeField(WritableField): else: return parsed.time() - time_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'HH:MM[:ss[.uuuuuu]]') - msg = self.error_messages['invalid'] % get_readable_date_format(time_input_formats) + msg = self.error_messages['invalid'] % readable_time_formats(self.input_formats) raise ValidationError(msg) def to_native(self, value): if isinstance(value, datetime.datetime): value = value.time() - if self.output_format.lower() == ISO8601: + if self.format.lower() == ISO_8601: return value.isoformat() - return value.strftime(self.output_format) + return value.strftime(self.format) class IntegerField(WritableField): diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 02d751e1..eede0c5a 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -22,7 +22,7 @@ from __future__ import unicode_literals from django.conf import settings from django.utils import importlib -from rest_framework import ISO8601 +from rest_framework import ISO_8601 from rest_framework.compat import six @@ -82,19 +82,19 @@ DEFAULTS = { # Input and output formats 'DATE_INPUT_FORMATS': ( - ISO8601, + ISO_8601, ), - 'DATE_OUTPUT_FORMAT': ISO8601, + 'DATE_FORMAT': ISO_8601, 'DATETIME_INPUT_FORMATS': ( - ISO8601, + ISO_8601, ), - 'DATETIME_OUTPUT_FORMAT': ISO8601, + 'DATETIME_FORMAT': ISO_8601, 'TIME_INPUT_FORMATS': ( - ISO8601, + ISO_8601, ), - 'TIME_OUTPUT_FORMAT': ISO8601, + 'TIME_FORMAT': ISO_8601, } diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index 17ef2f2c..28f18ed8 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -59,7 +59,7 @@ class BasicFieldTests(TestCase): PK fields other than AutoField fields should not be read_only by default. """ serializer = CharPrimaryKeyModelSerializer() - self.assertEquals(serializer.fields['id'].read_only, False) + self.assertEqual(serializer.fields['id'].read_only, False) class DateFieldTest(TestCase): @@ -134,7 +134,7 @@ class DateFieldTest(TestCase): try: f.from_native('1984-13-31') except validators.ValidationError as e: - self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY-MM-DD"]) + self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]"]) else: self.fail("ValidationError was not properly raised") @@ -147,7 +147,7 @@ class DateFieldTest(TestCase): try: f.from_native('1984 -- 31') except validators.ValidationError as e: - self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY-MM-DD"]) + self.assertEqual(e.messages, ["Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]"]) else: self.fail("ValidationError was not properly raised") @@ -165,7 +165,7 @@ class DateFieldTest(TestCase): """ Make sure to_native() returns correct custom format. """ - f = serializers.DateField(output_format="%Y - %m.%d") + f = serializers.DateField(format="%Y - %m.%d") result_1 = f.to_native(datetime.date(1984, 7, 31)) @@ -221,7 +221,7 @@ class DateTimeFieldTest(TestCase): try: f.from_native('1984-07-31 04:31:59') except validators.ValidationError as e: - self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: YYYY -- HH:MM"]) + self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: YYYY -- hh:mm"]) else: self.fail("ValidationError was not properly raised") @@ -253,7 +253,7 @@ class DateTimeFieldTest(TestCase): f.from_native('04:61:59') except validators.ValidationError as e: self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " - "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"]) + "YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HHMM|-HHMM|Z]"]) else: self.fail("ValidationError was not properly raised") @@ -267,7 +267,7 @@ class DateTimeFieldTest(TestCase): f.from_native('04 -- 31') except validators.ValidationError as e: self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " - "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"]) + "YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HHMM|-HHMM|Z]"]) else: self.fail("ValidationError was not properly raised") @@ -291,7 +291,7 @@ class DateTimeFieldTest(TestCase): """ Make sure to_native() returns correct custom format. """ - f = serializers.DateTimeField(output_format="%Y - %H:%M") + f = serializers.DateTimeField(format="%Y - %H:%M") result_1 = f.to_native(datetime.datetime(1984, 7, 31)) result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31)) @@ -353,7 +353,7 @@ class TimeFieldTest(TestCase): try: f.from_native('04:31:59') except validators.ValidationError as e: - self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: HH -- MM"]) + self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: hh -- mm"]) else: self.fail("ValidationError was not properly raised") @@ -385,7 +385,7 @@ class TimeFieldTest(TestCase): f.from_native('04:61:59') except validators.ValidationError as e: self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " - "HH:MM[:ss[.uuuuuu]]"]) + "hh:mm[:ss[.uuuuuu]]"]) else: self.fail("ValidationError was not properly raised") @@ -399,7 +399,7 @@ class TimeFieldTest(TestCase): f.from_native('04 -- 31') except validators.ValidationError as e: self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " - "HH:MM[:ss[.uuuuuu]]"]) + "hh:mm[:ss[.uuuuuu]]"]) else: self.fail("ValidationError was not properly raised") @@ -420,11 +420,11 @@ class TimeFieldTest(TestCase): """ Make sure to_native() returns correct custom format. """ - f = serializers.TimeField(output_format="%H - %S [%f]") + f = serializers.TimeField(format="%H - %S [%f]") result_1 = f.to_native(datetime.time(4, 31)) result_2 = f.to_native(datetime.time(4, 31, 59)) result_3 = f.to_native(datetime.time(4, 31, 59, 200)) self.assertEqual('04 - 00 [000000]', result_1) self.assertEqual('04 - 59 [000000]', result_2) - self.assertEqual('04 - 59 [000200]', result_3) \ No newline at end of file + self.assertEqual('04 - 59 [000200]', result_3) diff --git a/rest_framework/utils/dates.py b/rest_framework/utils/dates.py deleted file mode 100644 index f094f72d..00000000 --- a/rest_framework/utils/dates.py +++ /dev/null @@ -1,14 +0,0 @@ -def get_readable_date_format(date_format): - mapping = [("%Y", "YYYY"), - ("%y", "YY"), - ("%m", "MM"), - ("%b", "[Jan through Dec]"), - ("%B", "[January through December]"), - ("%d", "DD"), - ("%H", "HH"), - ("%M", "MM"), - ("%S", "SS"), - ("%f", "uuuuuu")] - for k, v in mapping: - date_format = date_format.replace(k, v) - return date_format \ No newline at end of file -- cgit v1.2.3