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):