[Django] #30261: Calling a form method _html_output modifies the self._errors dict for NON_FIELD_ERRORS if there are hidden field with errors

40 views
Skip to first unread message

Django

unread,
Mar 17, 2019, 2:11:27 PM3/17/19
to django-...@googlegroups.com
#30261: Calling a form method _html_output modifies the self._errors dict for
NON_FIELD_ERRORS if there are hidden field with errors
--------------------------------------+-----------------------------
Reporter: bmampaey | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 2.1
Severity: Normal | Keywords: form errors
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
--------------------------------------+-----------------------------
Each time the _html_output method of a form is called, it appends the
errors of the hidden field errors to the NON_FIELD_ERRORS (__all__) entry.

This happen for example when the form methods as_p() as_table() as_ul()
are called multiple time, or any other method that themselves call one of
them.

For example, a test form with an hidden input field that add errors during
the clean call.

{{{
Python 3.6.5 (default, Apr 25 2018, 14:26:36)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import django

In [2]: django.__version__
Out[2]: '2.1.7'

In [3]: from django import forms
...:

In [4]: class TestForm(forms.Form):
...: hidden_input = forms.CharField(widget=forms.HiddenInput)
...:
...: def clean(self):
...: self.add_error(None, 'Form error')
...: self.add_error('hidden_input', 'Hidden input error')
...:

In [5]: test_form = TestForm({})

In [6]: test_form.errors
Out[6]:
{'hidden_input': ['This field is required.', 'Hidden input error'],
'__all__': ['Form error']}

In [7]: print(test_form.as_table())
<tr><td colspan="2"><ul class="errorlist nonfield"><li>Form
error</li><li>(Hidden field hidden_input) This field is
required.</li><li>(Hidden field hidden_input) Hidden input
error</li></ul><input type="hidden" name="hidden_input"
id="id_hidden_input"></td></tr>

In [8]: test_form.errors
Out[8]:
{'hidden_input': ['This field is required.', 'Hidden input error'],
'__all__': ['Form error', '(Hidden field hidden_input) This field is
required.', '(Hidden field hidden_input) Hidden input error']}

In [9]: print(test_form.as_table())
<tr><td colspan="2"><ul class="errorlist nonfield"><li>Form
error</li><li>(Hidden field hidden_input) This field is
required.</li><li>(Hidden field hidden_input) Hidden input
error</li><li>(Hidden field hidden_input) This field is
required.</li><li>(Hidden field hidden_input) Hidden input
error</li></ul><input type="hidden" name="hidden_input"
id="id_hidden_input"></td></tr>

In [10]: test_form.errors
Out[10]:
{'hidden_input': ['This field is required.', 'Hidden input error'],
'__all__': ['Form error', '(Hidden field hidden_input) This field is
required.', '(Hidden field hidden_input) Hidden input error', '(Hidden
field hidden_input) This field is required.', '(Hidden field hidden_input)
Hidden input error']}

In [11]: test_form.non_field_errors()
Out[11]: ['Form error', '(Hidden field hidden_input) This field is
required.', '(Hidden field hidden_input) Hidden input error', '(Hidden
field hidden_input) This field is required.', '(Hidden field hidden_input)
Hidden input error']
}}}

This bug affects probably also version 2.2.

A simple fix would be to use a copy of the error list before adding the
hidden field errors in the file django/forms/forms.py:

{{{
--- forms.py 2019-03-17 18:59:04.000000000 +0100
+++ forms_fixed.py 2019-03-17 19:00:08.000000000 +0100
@@ -194,7 +194,7 @@

def _html_output(self, normal_row, error_row, row_ender,
help_text_html, errors_on_separate_row):
"Output HTML. Used by as_table(), as_ul(), as_p()."
- top_errors = self.non_field_errors() # Errors that should be
displayed above all fields.
+ top_errors = self.non_field_errors().copy() # Errors that should
be displayed above all fields.
output, hidden_fields = [], []

for name, field in self.fields.items():
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/30261>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Mar 17, 2019, 3:27:54 PM3/17/19
to django-...@googlegroups.com
#30261: Calling a form method _html_output modifies the self._errors dict for
NON_FIELD_ERRORS if there are hidden field with errors
-----------------------------+------------------------------------

Reporter: bmampaey | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: form errors | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+------------------------------------
Changes (by Simon Charette):

* version: 2.1 => master
* stage: Unreviewed => Accepted


Comment:

I didn't reproduce but the report and the suggested patch make sense,
accepting on that basis.

Are you interested in submitting a Github pull request incorporating your
patch and a regression test?

--
Ticket URL: <https://code.djangoproject.com/ticket/30261#comment:1>

Django

unread,
Mar 30, 2019, 8:29:12 AM3/30/19
to django-...@googlegroups.com
#30261: Calling a form method _html_output modifies the self._errors dict for
NON_FIELD_ERRORS if there are hidden field with errors
-------------------------------------+-------------------------------------
Reporter: Benjamin Mampaey | Owner: Abhishek
| Bera
Type: Bug | Status: assigned

Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: form errors | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Abhishek Bera):

* owner: nobody => Abhishek Bera
* status: new => assigned


--
Ticket URL: <https://code.djangoproject.com/ticket/30261#comment:2>

Django

unread,
Feb 12, 2020, 6:32:47 AM2/12/20
to django-...@googlegroups.com
#30261: Calling a form method _html_output modifies the self._errors dict for
NON_FIELD_ERRORS if there are hidden field with errors
-------------------------------------+-------------------------------------
Reporter: Benjamin Mampaey | Owner: Hasan
| Ramezani

Type: Bug | Status: assigned
Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: form errors | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Hasan Ramezani):

* owner: Abhishek Bera => Hasan Ramezani
* has_patch: 0 => 1


--
Ticket URL: <https://code.djangoproject.com/ticket/30261#comment:3>

Django

unread,
Feb 13, 2020, 2:13:42 AM2/13/20
to django-...@googlegroups.com
#30261: Calling a form method _html_output modifies the self._errors dict for
NON_FIELD_ERRORS if there are hidden field with errors
-------------------------------------+-------------------------------------
Reporter: Benjamin Mampaey | Owner: Hasan
| Ramezani
Type: Bug | Status: assigned
Component: Forms | Version: master
Severity: Normal | Resolution:
Keywords: form errors | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by felixxm):

* stage: Accepted => Ready for checkin


--
Ticket URL: <https://code.djangoproject.com/ticket/30261#comment:4>

Django

unread,
Feb 13, 2020, 2:31:52 AM2/13/20
to django-...@googlegroups.com
#30261: Calling a form method _html_output modifies the self._errors dict for
NON_FIELD_ERRORS if there are hidden field with errors
-------------------------------------+-------------------------------------
Reporter: Benjamin Mampaey | Owner: Hasan
| Ramezani
Type: Bug | Status: closed
Component: Forms | Version: master
Severity: Normal | Resolution: fixed

Keywords: form errors | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak <felisiak.mariusz@…>):

* status: assigned => closed
* resolution: => fixed


Comment:

In [changeset:"49275c548887769cd70bbd85a3b125491f0c4062" 49275c54]:
{{{
#!CommitTicketReference repository=""
revision="49275c548887769cd70bbd85a3b125491f0c4062"
Fixed #30261 -- Prevented Form._html_output() from mutating errors if
hidden fields have errors.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/30261#comment:5>

Reply all
Reply to author
Forward
0 new messages