Skip to content

Commit 7326681

Browse files
author
Boris Pleshakov
committed
f progress
1 parent 873b48e commit 7326681

File tree

2 files changed

+39
-18
lines changed

2 files changed

+39
-18
lines changed

example/tests/test_errors.py

+26-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import pytest
2-
from django.conf.urls import url
32
from django.test import override_settings
4-
from django.urls import reverse
3+
from django.urls import reverse, path
54

65
from example.models import Blog
76
from rest_framework_json_api import serializers
@@ -20,6 +19,7 @@ def validate_data(self, value):
2019
class CommentSerializer(serializers.Serializer):
2120
attachments = CommentAttachmentSerializer(many=True, required=False)
2221
attachment = CommentAttachmentSerializer(required=False)
22+
one_more_attachment = CommentAttachmentSerializer(required=False)
2323
body = serializers.CharField(allow_null=False, required=True)
2424

2525

@@ -47,8 +47,8 @@ def post(self, request, *args, **kwargs):
4747

4848

4949
urlpatterns = [
50-
url(r'^entries-nested/$', DummyTestView.as_view(),
51-
name='entries-nested-list')
50+
path(r'^entries-nested/$', DummyTestView.as_view(),
51+
name='entries-nested-list')
5252
]
5353

5454

@@ -57,7 +57,7 @@ def some_blog(db):
5757
return Blog.objects.create(name='Some Blog', tagline="It's a blog")
5858

5959

60-
def perform_error_test(client, data, expected_pointer):
60+
def perform_error_test(client, data, expected_pointer, errors_count=1):
6161
with override_settings(
6262
JSON_API_SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE=True,
6363
ROOT_URLCONF=__name__
@@ -67,7 +67,7 @@ def perform_error_test(client, data, expected_pointer):
6767

6868
errors = response.data
6969

70-
assert len(errors) == 1
70+
assert len(errors) == errors_count
7171
assert errors[0]['source']['pointer'] == expected_pointer
7272

7373

@@ -204,6 +204,26 @@ def test_third_level_dict_error(client, some_blog):
204204
perform_error_test(client, data, '/data/attributes/comments/0/attachment/data')
205205

206206

207+
def test_many_third_level_dict_errors(client, some_blog):
208+
data = {
209+
'data': {
210+
'type': 'entries',
211+
'attributes': {
212+
'blog': some_blog.pk,
213+
'body_text': 'body_text',
214+
'headline': 'headline',
215+
'comments': [
216+
{
217+
'attachment': {}
218+
}
219+
]
220+
}
221+
}
222+
}
223+
224+
perform_error_test(client, data, '/data/attributes/comments/0/body', 2)
225+
226+
207227
@pytest.mark.filterwarning('default::DeprecationWarning:rest_framework_json_api.serializers')
208228
def test_deprecation_warning(recwarn):
209229
class DummyNestedSerializer(serializers.Serializer):

rest_framework_json_api/utils.py

+13-12
Original file line numberDiff line numberDiff line change
@@ -318,16 +318,7 @@ def format_drf_errors(response, context, exc):
318318
for field, error in response.data.items():
319319
field = format_value(field)
320320
pointer = '/data/attributes/{}'.format(field)
321-
# see if they passed a dictionary to ValidationError manually
322-
# The bit tricky problem is here. It is may be nested drf thing in format
323-
# name: error_object, or it may be custom error thrown by user. I guess,
324-
# if it is drf error, dict will always have single key
325-
if isinstance(error, dict):
326-
if len(error) > 1:
327-
errors.append(error)
328-
else:
329-
errors.extend(format_error_object(error, pointer, response))
330-
elif isinstance(exc, Http404) and isinstance(error, str):
321+
if isinstance(exc, Http404) and isinstance(error, str):
331322
# 404 errors don't have a pointer
332323
errors.extend(format_error_object(error, None, response))
333324
elif isinstance(error, str):
@@ -350,8 +341,18 @@ def format_drf_errors(response, context, exc):
350341
def format_error_object(message, pointer, response):
351342
errors = []
352343
if isinstance(message, dict):
353-
for k, v in message.items():
354-
errors.extend(format_error_object(v, pointer + '/{}'.format(k), response))
344+
links = message.pop('links', None)
345+
source = message.pop('source', None)
346+
is_custom_error = all([isinstance(x, str) for x in message.values()])
347+
if links is not None:
348+
message['links'] = links
349+
if source is not None:
350+
message['source'] = source
351+
if is_custom_error:
352+
errors.append(message)
353+
else:
354+
for k, v in message.items():
355+
errors.extend(format_error_object(v, pointer + '/{}'.format(k), response))
355356
elif isinstance(message, list):
356357
for num, error in enumerate(message):
357358
if isinstance(error, (list, dict)):

0 commit comments

Comments
 (0)