Skip to content

Commit 4abfa28

Browse files
authored
feat: Add some changes to ValidationError to support django style vadation errors (#8863)
1 parent 22d206c commit 4abfa28

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

rest_framework/exceptions.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,30 @@ class ValidationError(APIException):
144144
status_code = status.HTTP_400_BAD_REQUEST
145145
default_detail = _('Invalid input.')
146146
default_code = 'invalid'
147+
default_params = {}
147148

148-
def __init__(self, detail=None, code=None):
149+
def __init__(self, detail=None, code=None, params=None):
149150
if detail is None:
150151
detail = self.default_detail
151152
if code is None:
152153
code = self.default_code
154+
if params is None:
155+
params = self.default_params
153156

154157
# For validation failures, we may collect many errors together,
155158
# so the details should always be coerced to a list if not already.
156-
if isinstance(detail, tuple):
157-
detail = list(detail)
159+
if isinstance(detail, str):
160+
detail = [detail % params]
161+
elif isinstance(detail, ValidationError):
162+
detail = detail.detail
163+
elif isinstance(detail, (list, tuple)):
164+
final_detail = []
165+
for detail_item in detail:
166+
if isinstance(detail_item, ValidationError):
167+
final_detail += detail_item.detail
168+
else:
169+
final_detail += [detail_item % params if isinstance(detail_item, str) else detail_item]
170+
detail = final_detail
158171
elif not isinstance(detail, dict) and not isinstance(detail, list):
159172
detail = [detail]
160173

tests/test_validation_error.py

+86
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,89 @@ def test_validation_error_details(self):
109109
assert len(error.detail) == 2
110110
assert str(error.detail[0]) == 'message1'
111111
assert str(error.detail[1]) == 'message2'
112+
113+
114+
class TestValidationErrorWithDjangoStyle(TestCase):
115+
def test_validation_error_details(self):
116+
error = ValidationError('Invalid value: %(value)s', params={'value': '42'})
117+
assert str(error.detail[0]) == 'Invalid value: 42'
118+
119+
def test_validation_error_details_tuple(self):
120+
error = ValidationError(
121+
detail=('Invalid value: %(value1)s', 'Invalid value: %(value2)s'),
122+
params={'value1': '42', 'value2': '43'},
123+
)
124+
assert isinstance(error.detail, list)
125+
assert len(error.detail) == 2
126+
assert str(error.detail[0]) == 'Invalid value: 42'
127+
assert str(error.detail[1]) == 'Invalid value: 43'
128+
129+
def test_validation_error_details_list(self):
130+
error = ValidationError(
131+
detail=['Invalid value: %(value1)s', 'Invalid value: %(value2)s', ],
132+
params={'value1': '42', 'value2': '43'}
133+
)
134+
assert isinstance(error.detail, list)
135+
assert len(error.detail) == 2
136+
assert str(error.detail[0]) == 'Invalid value: 42'
137+
assert str(error.detail[1]) == 'Invalid value: 43'
138+
139+
def test_validation_error_details_validation_errors(self):
140+
error = ValidationError(
141+
detail=ValidationError(
142+
detail='Invalid value: %(value1)s',
143+
params={'value1': '42'},
144+
),
145+
)
146+
assert isinstance(error.detail, list)
147+
assert len(error.detail) == 1
148+
assert str(error.detail[0]) == 'Invalid value: 42'
149+
150+
def test_validation_error_details_validation_errors_list(self):
151+
error = ValidationError(
152+
detail=[
153+
ValidationError(
154+
detail='Invalid value: %(value1)s',
155+
params={'value1': '42'},
156+
),
157+
ValidationError(
158+
detail='Invalid value: %(value2)s',
159+
params={'value2': '43'},
160+
),
161+
'Invalid value: %(value3)s'
162+
],
163+
params={'value3': '44'}
164+
)
165+
assert isinstance(error.detail, list)
166+
assert len(error.detail) == 3
167+
assert str(error.detail[0]) == 'Invalid value: 42'
168+
assert str(error.detail[1]) == 'Invalid value: 43'
169+
assert str(error.detail[2]) == 'Invalid value: 44'
170+
171+
def test_validation_error_details_validation_errors_nested_list(self):
172+
error = ValidationError(
173+
detail=[
174+
ValidationError(
175+
detail='Invalid value: %(value1)s',
176+
params={'value1': '42'},
177+
),
178+
ValidationError(
179+
detail=[
180+
'Invalid value: %(value2)s',
181+
ValidationError(
182+
detail='Invalid value: %(value3)s',
183+
params={'value3': '44'},
184+
)
185+
],
186+
params={'value2': '43'},
187+
),
188+
'Invalid value: %(value4)s'
189+
],
190+
params={'value4': '45'}
191+
)
192+
assert isinstance(error.detail, list)
193+
assert len(error.detail) == 4
194+
assert str(error.detail[0]) == 'Invalid value: 42'
195+
assert str(error.detail[1]) == 'Invalid value: 43'
196+
assert str(error.detail[2]) == 'Invalid value: 44'
197+
assert str(error.detail[3]) == 'Invalid value: 45'

0 commit comments

Comments
 (0)