diff --git a/django/forms/utils.py b/django/forms/utils.py index e3151c9390..587cea85a3 100644 --- a/django/forms/utils.py +++ b/django/forms/utils.py @@ -51,8 +51,11 @@ class ErrorDict(dict): def as_data(self): return {f: e.as_data() for f, e in self.items()} + def get_json_data(self, escape_html=False): + return {f: e.get_json_data(escape_html) for f, e in self.items()} + def as_json(self, escape_html=False): - return json.dumps({f: e.get_json_data(escape_html) for f, e in self.items()}) + return json.dumps(self.get_json_data(escape_html)) def as_ul(self): if not self: diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt index fda7472105..72ae044090 100644 --- a/docs/ref/forms/api.txt +++ b/docs/ref/forms/api.txt @@ -165,6 +165,17 @@ If for some reason you don't want to use client-side escaping, you can also set ``escape_html=True`` and error messages will be escaped so you can use them directly in HTML. +.. method:: Form.errors.get_json_data(escape_html=False) + +.. versionadded:: 2.0 + +Returns the errors as a dictionary suitable for serializing to JSON. +:meth:`Form.errors.as_json()` returns serialized JSON, while this returns the +error data before it's serialized. + +The ``escape_html`` parameter behaves as described in +:meth:`Form.errors.as_json()`. + .. method:: Form.add_error(field, error) This method allows adding errors to specific fields from within the diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt index ee9ae181b4..e4b7110560 100644 --- a/docs/releases/2.0.txt +++ b/docs/releases/2.0.txt @@ -166,6 +166,10 @@ Forms HTML attributes for the ``DateInput`` and ``TimeInput`` (or hidden) subwidgets. +* The new :meth:`Form.errors.get_json_data() + ` method returns form errors as + a dictionary suitable for including in a JSON response. + Generic Views ~~~~~~~~~~~~~ diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index 63209a1f62..cc73819091 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -3216,13 +3216,14 @@ Good luck picking a username that doesn't already exist.

for error in control: self.assertInHTML(error, errors) - errors = json.loads(form.errors.as_json()) + errors = form.errors.get_json_data() control = { 'foo': [{'code': 'required', 'message': 'This field is required.'}], 'bar': [{'code': 'required', 'message': 'This field is required.'}], '__all__': [{'code': 'secret', 'message': 'Non-field error.'}] } self.assertEqual(errors, control) + self.assertEqual(json.dumps(errors), form.errors.as_json()) def test_error_dict_as_json_escape_html(self): """#21962 - adding html escape flag to ErrorDict""" @@ -3247,8 +3248,13 @@ Good luck picking a username that doesn't already exist.

errors = json.loads(form.errors.as_json()) self.assertEqual(errors, control) + escaped_error = '<p>Non-field error.</p>' + self.assertEqual( + form.errors.get_json_data(escape_html=True)['__all__'][0]['message'], + escaped_error + ) errors = json.loads(form.errors.as_json(escape_html=True)) - control['__all__'][0]['message'] = '<p>Non-field error.</p>' + control['__all__'][0]['message'] = escaped_error self.assertEqual(errors, control) def test_error_list(self): @@ -3270,10 +3276,12 @@ Good luck picking a username that doesn't already exist.

'' ) + errors = e.get_json_data() self.assertEqual( - json.loads(e.as_json()), + errors, [{"message": "Foo", "code": ""}, {"message": "Foobar", "code": "foobar"}] ) + self.assertEqual(json.dumps(errors), e.as_json()) def test_error_list_class_not_specified(self): e = ErrorList()