diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index f587d10fd9..236087bde7 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -14,6 +14,7 @@ from django.utils.translation import ungettext from rest_framework import status +from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList def _force_text_recursive(data): @@ -22,14 +23,20 @@ def _force_text_recursive(data): lazy translation strings into plain text. """ if isinstance(data, list): - return [ + ret = [ _force_text_recursive(item) for item in data ] + if isinstance(data, ReturnList): + return ReturnList(ret, serializer=data.serializer) + return data elif isinstance(data, dict): - return dict([ + ret = dict([ (key, _force_text_recursive(value)) for key, value in data.items() ]) + if isinstance(data, ReturnDict): + return ReturnDict(ret, serializer=data.serializer) + return data return force_text(data) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index fa3a53374e..60ee7e5cce 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -204,7 +204,7 @@ def is_valid(self, raise_exception=False): self._errors = {} if self._errors and raise_exception: - raise ValidationError(self._errors) + raise ValidationError(self.errors) return not bool(self._errors) diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py index 245c5f7176..229a46d0b6 100644 --- a/rest_framework/utils/serializer_helpers.py +++ b/rest_framework/utils/serializer_helpers.py @@ -72,7 +72,7 @@ def __repr__(self): )) def as_form_field(self): - value = force_text(self.value) + value = '' if self.value is None else force_text(self.value) return self.__class__(self._field, value, self.errors, self._prefix) @@ -100,7 +100,7 @@ def as_form_field(self): if isinstance(value, (list, dict)): values[key] = value else: - values[key] = force_text(value) + values[key] = '' if value is None else force_text(value) return self.__class__(self._field, values, self.errors, self._prefix) diff --git a/tests/test_generics.py b/tests/test_generics.py index 0647119bf4..219a83a5d6 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -145,6 +145,16 @@ def test_post_cannot_set_id(self): created = self.objects.get(id=4) self.assertEqual(created.text, 'foobar') + def test_post_error_root_view(self): + """ + POST requests to ListCreateAPIView in HTML should include a form error. + """ + data = {'text': 'foobar' * 100} + request = factory.post('/', data, HTTP_ACCEPT='text/html') + response = self.view(request).render() + expected_error = 'Ensure this field has no more than 100 characters.' + self.assertIn(expected_error, response.rendered_content.decode('utf-8')) + EXPECTED_QUERIES_FOR_PUT = 3 if django.VERSION < (1, 6) else 2 @@ -282,6 +292,16 @@ def test_patch_cannot_create_an_object(self): self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertFalse(self.objects.filter(id=999).exists()) + def test_put_error_instance_view(self): + """ + Incorrect PUT requests in HTML should include a form error. + """ + data = {'text': 'foobar' * 100} + request = factory.put('/', data, HTTP_ACCEPT='text/html') + response = self.view(request, pk=1).render() + expected_error = 'Ensure this field has no more than 100 characters.' + self.assertIn(expected_error, response.rendered_content.decode('utf-8')) + class TestFKInstanceView(TestCase): def setUp(self):