Skip to content

Commit 29b4ab2

Browse files
author
Ryan P Kilby
committed
Nest ListField/DictField errors under the idx/key
1 parent c4132e5 commit 29b4ab2

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

rest_framework/fields.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,14 +1626,28 @@ def to_internal_value(self, data):
16261626
self.fail('not_a_list', input_type=type(data).__name__)
16271627
if not self.allow_empty and len(data) == 0:
16281628
self.fail('empty')
1629-
return [self.child.run_validation(item) for item in data]
1629+
return self.run_child_validation(data)
16301630

16311631
def to_representation(self, data):
16321632
"""
16331633
List of object instances -> List of dicts of primitive datatypes.
16341634
"""
16351635
return [self.child.to_representation(item) if item is not None else None for item in data]
16361636

1637+
def run_child_validation(self, data):
1638+
result = []
1639+
errors = {}
1640+
1641+
for idx, item in enumerate(data):
1642+
try:
1643+
result.append(self.child.run_validation(item))
1644+
except ValidationError as e:
1645+
errors[idx] = e.detail
1646+
1647+
if not errors:
1648+
return result
1649+
raise ValidationError(errors)
1650+
16371651

16381652
class DictField(Field):
16391653
child = _UnvalidatedField()
@@ -1669,10 +1683,7 @@ def to_internal_value(self, data):
16691683
data = html.parse_html_dict(data)
16701684
if not isinstance(data, dict):
16711685
self.fail('not_a_dict', input_type=type(data).__name__)
1672-
return {
1673-
six.text_type(key): self.child.run_validation(value)
1674-
for key, value in data.items()
1675-
}
1686+
return self.run_child_validation(data)
16761687

16771688
def to_representation(self, value):
16781689
"""
@@ -1683,6 +1694,22 @@ def to_representation(self, value):
16831694
for key, val in value.items()
16841695
}
16851696

1697+
def run_child_validation(self, data):
1698+
result = {}
1699+
errors = {}
1700+
1701+
for key, value in data.items():
1702+
key = six.text_type(key)
1703+
1704+
try:
1705+
result[key] = self.child.run_validation(value)
1706+
except ValidationError as e:
1707+
errors[key] = e.detail
1708+
1709+
if not errors:
1710+
return result
1711+
raise ValidationError(errors)
1712+
16861713

16871714
class JSONField(Field):
16881715
default_error_messages = {

tests/test_fields.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,7 @@ class TestListField(FieldValues):
17671767
]
17681768
invalid_inputs = [
17691769
('not a list', ['Expected a list of items but got type "str".']),
1770-
([1, 2, 'error'], ['A valid integer is required.']),
1770+
([1, 2, 'error', 'error'], {2: ['A valid integer is required.'], 3: ['A valid integer is required.']}),
17711771
({'one': 'two'}, ['Expected a list of items but got type "dict".'])
17721772
]
17731773
outputs = [
@@ -1840,7 +1840,7 @@ class TestDictField(FieldValues):
18401840
({'a': 1, 'b': '2', 3: 3}, {'a': '1', 'b': '2', '3': '3'}),
18411841
]
18421842
invalid_inputs = [
1843-
({'a': 1, 'b': None}, ['This field may not be null.']),
1843+
({'a': 1, 'b': None, 'c': None}, {'b': ['This field may not be null.'], 'c': ['This field may not be null.']}),
18441844
('not a dict', ['Expected a dictionary of items but got type "str".']),
18451845
]
18461846
outputs = [

0 commit comments

Comments
 (0)