Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DateField and DateTimeField not handling empty values correctly #2687

Closed
jannon opened this issue Mar 13, 2015 · 6 comments
Closed

DateField and DateTimeField not handling empty values correctly #2687

jannon opened this issue Mar 13, 2015 · 6 comments
Labels
Milestone

Comments

@jannon
Copy link

jannon commented Mar 13, 2015

This results in the same error as mentioned in #2656, but has a different reproduction and implications. A test case like the following:

class MyModel(models.Model):
    my_date = models.DateField(null=True, blank=True)
    other_field = models.CharField(max_length=100)


class MySerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel


class MyView(generics.ListCreateAPIView):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer


class TestMySerializer(TestCase):
    def setUp(self):
        self.view = MyView.as_view()

    def test_model_save_works(self):
        obj = MyModel.objects.create(other_field='foo')
        assert obj.other_field == ''foo"

    def test_post_root_view(self):
        """
        POST requests to ListCreateAPIView should create a new object.
        """
        data = {'other_field': 'bar'}
        request = factory.post('/', data, format='json')
        response = self.view(request).render()
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

Results in an error like:

Traceback (most recent call last):
  File "tests.py", line 10, in test_post_root_view
     response = self.view(request).render()
  File "/path/to/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/path/to/rest_framework/viewsets.py", line 85, in view
    return self.dispatch(request, *args, **kwargs)
  File "/path/to/rest_framework/views.py", line 452, in dispatch
    response = self.handle_exception(exc)
  File "/path/to/rest_framework/views.py", line 449, in dispatch
    response = handler(request, *args, **kwargs)
  File "/path/to/rest_framework/mixins.py", line 57, in retrieve
    return Response(serializer.data)
  File "/path/to/rest_framework/serializers.py", line 467, in data
    ret = super(Serializer, self).data
  File "/path/to/rest_framework/serializers.py", line 213, in data
    self._data = self.to_representation(self.instance)
  File "/path/to/rest_framework/serializers.py", line 436, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/path/to/rest_framework/fields.py", line 940, in to_representation
    return value.isoformat()
AttributeError: 'str' object has no attribute 'isoformat'

This is because the submitted data does not contain a 'my_date' field (which is valid in this situation) and that results in the empty string being sent as the value parameter DateField.to_representation, which proceeds to attempt to call isoformat() on it.

I'm happy to submit a PR, but I wanted to first check that I wasn't missing something and check to see how you actually wanted to handle it. Maybe just return the value if it's None or ''? Or more complex string handling as requested in #2656? Or maybe something else should happen earlier to prevent empty values from even getting to to_representation?

@felixcheruiyot
Copy link

I'm experiencing the same problem 'unicode' object has no attribute 'isoformat' with DateField.

@felixcheruiyot
Copy link

I have just realized using serializers fields definition kinda solve this problem. See. Here is how I'm using it:

class MySerializer(serializers.ModelSerializer):
    deadline = serializers.DateField(format=None, input_formats=None)
    class Meta:
        model = MyModel
        fields = (
            'id',
            'title',
            'deadline',
            'created_at',
            'updated_at',
        )
       depth = 1

It works when my deadline field has values. My problem now is that my deadline field is not mandatory, so trying adding more option to it fails to behave has expected. I have tried playing with required=False, allow_null=True, read_only=True from the Core arguments but it fails and throws date format error:

value has an invalid date format. It must be in YYYY-MM-DD format.

@ryangallen
Copy link
Contributor

@tomchristie I can work on a fix for this; would the appropriate test output dict be...?

outputs = {
    datetime.date(2001, 1, 1): '2001-01-01',
    '2001-01-01': '2001-01-01',
    '': None
}

ryangallen pushed a commit to ryangallen/django-rest-framework that referenced this issue Apr 24, 2015
@tomchristie
Copy link
Member

@ryangallen That looks right to me.

@ryangallen
Copy link
Contributor

Cool, here's a pull req. #2869

tomchristie added a commit that referenced this issue May 1, 2015
DateField to_representation can handle str and empty values. Fixes #2656, #2687.
@tomchristie
Copy link
Member

Closed by #2869.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants