Skip to content

Commit 9d136ab

Browse files
committed
Merge pull request #3179 from tomchristie/browsable-api-errors
Errors in browsable API on error.
2 parents 6e6fa89 + d14bc3c commit 9d136ab

File tree

4 files changed

+32
-5
lines changed

4 files changed

+32
-5
lines changed

rest_framework/exceptions.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from django.utils.translation import ungettext
1515

1616
from rest_framework import status
17+
from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList
1718

1819

1920
def _force_text_recursive(data):
@@ -22,14 +23,20 @@ def _force_text_recursive(data):
2223
lazy translation strings into plain text.
2324
"""
2425
if isinstance(data, list):
25-
return [
26+
ret = [
2627
_force_text_recursive(item) for item in data
2728
]
29+
if isinstance(data, ReturnList):
30+
return ReturnList(ret, serializer=data.serializer)
31+
return data
2832
elif isinstance(data, dict):
29-
return dict([
33+
ret = dict([
3034
(key, _force_text_recursive(value))
3135
for key, value in data.items()
3236
])
37+
if isinstance(data, ReturnDict):
38+
return ReturnDict(ret, serializer=data.serializer)
39+
return data
3340
return force_text(data)
3441

3542

rest_framework/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def is_valid(self, raise_exception=False):
204204
self._errors = {}
205205

206206
if self._errors and raise_exception:
207-
raise ValidationError(self._errors)
207+
raise ValidationError(self.errors)
208208

209209
return not bool(self._errors)
210210

rest_framework/utils/serializer_helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def __repr__(self):
7272
))
7373

7474
def as_form_field(self):
75-
value = force_text(self.value)
75+
value = '' if self.value is None else force_text(self.value)
7676
return self.__class__(self._field, value, self.errors, self._prefix)
7777

7878

@@ -100,7 +100,7 @@ def as_form_field(self):
100100
if isinstance(value, (list, dict)):
101101
values[key] = value
102102
else:
103-
values[key] = force_text(value)
103+
values[key] = '' if value is None else force_text(value)
104104
return self.__class__(self._field, values, self.errors, self._prefix)
105105

106106

tests/test_generics.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ def test_post_cannot_set_id(self):
145145
created = self.objects.get(id=4)
146146
self.assertEqual(created.text, 'foobar')
147147

148+
def test_post_error_root_view(self):
149+
"""
150+
POST requests to ListCreateAPIView in HTML should include a form error.
151+
"""
152+
data = {'text': 'foobar' * 100}
153+
request = factory.post('/', data, HTTP_ACCEPT='text/html')
154+
response = self.view(request).render()
155+
expected_error = '<span class="help-block">Ensure this field has no more than 100 characters.</span>'
156+
self.assertIn(expected_error, response.rendered_content.decode('utf-8'))
157+
148158

149159
EXPECTED_QUERIES_FOR_PUT = 3 if django.VERSION < (1, 6) else 2
150160

@@ -282,6 +292,16 @@ def test_patch_cannot_create_an_object(self):
282292
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
283293
self.assertFalse(self.objects.filter(id=999).exists())
284294

295+
def test_put_error_instance_view(self):
296+
"""
297+
Incorrect PUT requests in HTML should include a form error.
298+
"""
299+
data = {'text': 'foobar' * 100}
300+
request = factory.put('/', data, HTTP_ACCEPT='text/html')
301+
response = self.view(request, pk=1).render()
302+
expected_error = '<span class="help-block">Ensure this field has no more than 100 characters.</span>'
303+
self.assertIn(expected_error, response.rendered_content.decode('utf-8'))
304+
285305

286306
class TestFKInstanceView(TestCase):
287307
def setUp(self):

0 commit comments

Comments
 (0)