diff options
| -rw-r--r-- | rest_framework/fields.py | 40 | ||||
| -rw-r--r-- | rest_framework/settings.py | 21 | ||||
| -rw-r--r-- | rest_framework/tests/fields.py | 503 | ||||
| -rw-r--r-- | rest_framework/tests/filterset.py | 13 | ||||
| -rw-r--r-- | rest_framework/tests/pagination.py | 4 | ||||
| -rw-r--r-- | rest_framework/tests/serializer.py | 2 | 
6 files changed, 310 insertions, 273 deletions
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 e76079c9..ddedd6f9 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() @@ -140,273 +63,347 @@ class BasicFieldTests(TestCase):  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()) +    """ +    Tests for the DateFieldTest from_native() and to_native() behavior +    """ -    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(datetime.date(1984, 1, 31), result) -        self.assertEqual(result, datetime.date(1984, 7, 31)) +    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)) + +        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) -        serializer = TimeObjectSerializer(data={'time': '04:31:59'}) -        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") -    def test_valid_custom_time_input_formats(self): -        serializer = TimeObjectCustomFormatSerializer(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 = TimeObjectCustomFormatSerializer(data={'time': '043159'}) -        self.assertTrue(serializer.is_valid()) +        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_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']}) -    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']}) +class TimeFieldTest(TestCase): +    """ +    Tests for the TimeField from_native() and to_native() behavior +    """ -    def test_from_native(self): +    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")
\ No newline at end of file +            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 daea6e53..16f9a48e 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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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 b85ce144..c1efd4f5 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 671494b5..1c99375f 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -107,7 +107,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}  | 
