mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	Add better date / datetime validation (pull 2)
addition to #631 with update to master + timefield support
This commit is contained in:
		
							parent
							
								
									8da83f0df9
								
							
						
					
					
						commit
						bfff356dd3
					
				| 
						 | 
					@ -185,12 +185,20 @@ Corresponds to `django.forms.fields.RegexField`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A date representation.
 | 
					A date representation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Uses `DATE_INPUT_FORMATS` to validate date.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optionally takes `format` as parameter to replace the matching pattern.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Corresponds to `django.db.models.fields.DateField`
 | 
					Corresponds to `django.db.models.fields.DateField`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## DateTimeField
 | 
					## DateTimeField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A date and time representation.
 | 
					A date and time representation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Uses `DATETIME_INPUT_FORMATS` to validate date_time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optionally takes `format` as parameter to replace the matching pattern.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Corresponds to `django.db.models.fields.DateTimeField`
 | 
					Corresponds to `django.db.models.fields.DateTimeField`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When using `ModelSerializer` or `HyperlinkedModelSerializer`, note that any model fields with `auto_now=True` or `auto_now_add=True` will use serializer fields that are `read_only=True` by default.
 | 
					When using `ModelSerializer` or `HyperlinkedModelSerializer`, note that any model fields with `auto_now=True` or `auto_now_add=True` will use serializer fields that are `read_only=True` by default.
 | 
				
			||||||
| 
						 | 
					@ -207,6 +215,10 @@ If you want to override this behavior, you'll need to declare the `DateTimeField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A time representation.
 | 
					A time representation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Uses `TIME_INPUT_FORMATS` to validate time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optionally takes `format` as parameter to replace the matching pattern.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Corresponds to `django.db.models.fields.TimeField`
 | 
					Corresponds to `django.db.models.fields.TimeField`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## IntegerField
 | 
					## IntegerField
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,6 +44,9 @@ You can determine your currently installed version using `pip freeze`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Bugfix for serializer data being uncacheable with pickle protocol 0.
 | 
					* Bugfix for serializer data being uncacheable with pickle protocol 0.
 | 
				
			||||||
* Bugfixes for model field validation edge-cases.
 | 
					* Bugfixes for model field validation edge-cases.
 | 
				
			||||||
 | 
					* Support `DATE_INPUT_FORMATS` for `DateField` validation
 | 
				
			||||||
 | 
					* Support `DATETIME_INPUT_FORMATS` for `DateTimeField` validation
 | 
				
			||||||
 | 
					* Support `TIME_INPUT_FORMATS` for `TimeField` validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 2.2.1
 | 
					### 2.2.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@ from rest_framework.compat import BytesIO
 | 
				
			||||||
from rest_framework.compat import six
 | 
					from rest_framework.compat import six
 | 
				
			||||||
from rest_framework.compat import smart_text
 | 
					from rest_framework.compat import smart_text
 | 
				
			||||||
from rest_framework.compat import parse_time
 | 
					from rest_framework.compat import parse_time
 | 
				
			||||||
 | 
					from rest_framework.utils.dates import get_readable_date_format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def is_simple_callable(obj):
 | 
					def is_simple_callable(obj):
 | 
				
			||||||
| 
						 | 
					@ -447,13 +448,14 @@ class DateField(WritableField):
 | 
				
			||||||
    form_field_class = forms.DateField
 | 
					    form_field_class = forms.DateField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default_error_messages = {
 | 
					    default_error_messages = {
 | 
				
			||||||
        'invalid': _("'%s' value has an invalid date format. It must be "
 | 
					        'invalid': _(u"Date has wrong format. Use one of these formats instead: %s"),
 | 
				
			||||||
                     "in YYYY-MM-DD format."),
 | 
					 | 
				
			||||||
        'invalid_date': _("'%s' value has the correct format (YYYY-MM-DD) "
 | 
					 | 
				
			||||||
                          "but it is an invalid date."),
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    empty = None
 | 
					    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):
 | 
					    def from_native(self, value):
 | 
				
			||||||
        if value in validators.EMPTY_VALUES:
 | 
					        if value in validators.EMPTY_VALUES:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
| 
						 | 
					@ -468,15 +470,16 @@ class DateField(WritableField):
 | 
				
			||||||
        if isinstance(value, datetime.date):
 | 
					        if isinstance(value, datetime.date):
 | 
				
			||||||
            return value
 | 
					            return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for format in self.format:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
            parsed = parse_date(value)
 | 
					                parsed = datetime.datetime.strptime(value, format)
 | 
				
			||||||
            if parsed is not None:
 | 
					 | 
				
			||||||
                return parsed
 | 
					 | 
				
			||||||
            except (ValueError, TypeError):
 | 
					            except (ValueError, TypeError):
 | 
				
			||||||
            msg = self.error_messages['invalid_date'] % value
 | 
					                pass
 | 
				
			||||||
            raise ValidationError(msg)
 | 
					            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)
 | 
					        raise ValidationError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -486,16 +489,14 @@ class DateTimeField(WritableField):
 | 
				
			||||||
    form_field_class = forms.DateTimeField
 | 
					    form_field_class = forms.DateTimeField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default_error_messages = {
 | 
					    default_error_messages = {
 | 
				
			||||||
        'invalid': _("'%s' value has an invalid format. It must be in "
 | 
					        'invalid': _(u"Datetime has wrong format. Use one of these formats instead: %s"),
 | 
				
			||||||
                     "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."),
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    empty = None
 | 
					    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):
 | 
					    def from_native(self, value):
 | 
				
			||||||
        if value in validators.EMPTY_VALUES:
 | 
					        if value in validators.EMPTY_VALUES:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
| 
						 | 
					@ -516,23 +517,16 @@ class DateTimeField(WritableField):
 | 
				
			||||||
                value = timezone.make_aware(value, default_timezone)
 | 
					                value = timezone.make_aware(value, default_timezone)
 | 
				
			||||||
            return value
 | 
					            return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for format in self.format:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
            parsed = parse_datetime(value)
 | 
					                parsed = datetime.datetime.strptime(value, format)
 | 
				
			||||||
            if parsed is not None:
 | 
					            except (ValueError, TypeError):
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
                return parsed
 | 
					                return parsed
 | 
				
			||||||
        except (ValueError, TypeError):
 | 
					 | 
				
			||||||
            msg = self.error_messages['invalid_datetime'] % value
 | 
					 | 
				
			||||||
            raise ValidationError(msg)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        datetime_input_formats = '; '.join(self.format)
 | 
				
			||||||
            parsed = parse_date(value)
 | 
					        msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats)
 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
        raise ValidationError(msg)
 | 
					        raise ValidationError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -542,11 +536,14 @@ class TimeField(WritableField):
 | 
				
			||||||
    form_field_class = forms.TimeField
 | 
					    form_field_class = forms.TimeField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default_error_messages = {
 | 
					    default_error_messages = {
 | 
				
			||||||
        'invalid': _("'%s' value has an invalid format. It must be a valid "
 | 
					        'invalid': _(u"Time has wrong format. Use one of these formats instead: %s"),
 | 
				
			||||||
                     "time in the HH:MM[:ss[.uuuuuu]] format."),
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    empty = None
 | 
					    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):
 | 
					    def from_native(self, value):
 | 
				
			||||||
        if value in validators.EMPTY_VALUES:
 | 
					        if value in validators.EMPTY_VALUES:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
| 
						 | 
					@ -554,12 +551,16 @@ class TimeField(WritableField):
 | 
				
			||||||
        if isinstance(value, datetime.time):
 | 
					        if isinstance(value, datetime.time):
 | 
				
			||||||
            return value
 | 
					            return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for format in self.format:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
            parsed = parse_time(value)
 | 
					                parsed = datetime.datetime.strptime(value, format)
 | 
				
			||||||
            assert parsed is not None
 | 
					 | 
				
			||||||
            return parsed
 | 
					 | 
				
			||||||
            except (ValueError, TypeError):
 | 
					            except (ValueError, TypeError):
 | 
				
			||||||
            msg = self.error_messages['invalid'] % value
 | 
					                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)
 | 
					        raise ValidationError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,9 +3,13 @@ General serializer field tests.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
from __future__ import unicode_literals
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.test import TestCase
 | 
					from django.test import TestCase
 | 
				
			||||||
from django.core import validators
 | 
					from django.core import validators
 | 
				
			||||||
 | 
					from django.utils import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +22,21 @@ class CharPrimaryKeyModel(models.Model):
 | 
				
			||||||
    id = models.CharField(max_length=20, primary_key=True)
 | 
					    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 TimestampedModelSerializer(serializers.ModelSerializer):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = TimestampedModel
 | 
					        model = TimestampedModel
 | 
				
			||||||
| 
						 | 
					@ -28,6 +47,66 @@ class CharPrimaryKeyModelSerializer(serializers.ModelSerializer):
 | 
				
			||||||
        model = CharPrimaryKeyModel
 | 
					        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):
 | 
					class TimeFieldModel(models.Model):
 | 
				
			||||||
    clock = models.TimeField()
 | 
					    clock = models.TimeField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,37 +138,275 @@ class BasicFieldTests(TestCase):
 | 
				
			||||||
        serializer = CharPrimaryKeyModelSerializer()
 | 
					        serializer = CharPrimaryKeyModelSerializer()
 | 
				
			||||||
        self.assertEquals(serializer.fields['id'].read_only, False)
 | 
					        self.assertEquals(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()
 | 
					        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.
 | 
					        Make sure from_native() accepts a datetime.time instance.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        f = serializers.TimeField()
 | 
					        f = serializers.TimeField()
 | 
				
			||||||
        result = f.from_native(datetime.time(12, 34, 56))
 | 
					        result = f.from_native(datetime.time(12, 34, 56))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(result, 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()
 | 
					        f = serializers.TimeField()
 | 
				
			||||||
        result = f.from_native('')
 | 
					        result = f.from_native('')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(result, None)
 | 
					        self.assertEqual(result, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_TimeField_from_native_invalid_time(self):
 | 
					    def test_from_native_invalid_time(self):
 | 
				
			||||||
        f = serializers.TimeField()
 | 
					        f = serializers.TimeField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            f.from_native('12:69:12')
 | 
					            f.from_native('12:69:12')
 | 
				
			||||||
        except validators.ValidationError as e:
 | 
					        except validators.ValidationError as e:
 | 
				
			||||||
            self.assertEqual(e.messages, ["'12:69:12' value has an invalid "
 | 
					            self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: HH:MM:SS; HH:MM"])
 | 
				
			||||||
                                          "format. It must be a valid time "
 | 
					 | 
				
			||||||
                                          "in the HH:MM[:ss[.uuuuuu]] format."])
 | 
					 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.fail("ValidationError was not properly raised")
 | 
					            self.fail("ValidationError was not properly raised")
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_TimeFieldModelSerializer(self):
 | 
					 | 
				
			||||||
        serializer = TimeFieldModelSerializer()
 | 
					 | 
				
			||||||
        self.assertTrue(isinstance(serializer.fields['clock'], serializers.TimeField))
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								rest_framework/utils/dates.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								rest_framework/utils/dates.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user