[Django] #25548: Can't Form.add_error() in FormView.form_valid()

38 views
Skip to first unread message

Django

unread,
Oct 12, 2015, 7:24:29 PM10/12/15
to django-...@googlegroups.com
#25548: Can't Form.add_error() in FormView.form_valid()
---------------------------+-----------------------------------------------
Reporter: acatton | Owner: nobody
Type: | Status: new
Uncategorized |
Component: Generic | Version: master
views |
Severity: Normal | Keywords: performance FormView form_invalid
Triage Stage: | Has patch: 1
Unreviewed |
Easy pickings: 1 | UI/UX: 0
---------------------------+-----------------------------------------------
Let's consider this example:

{{{#!python
class MyView(FormView):
def form_valid(self, form):
value = form.cleaned_data['value']
try:
do_action(value)
except ValueError as e:
form.add_error(None, e.message)
return self.form_invalid(form)
return super().form_valid(form)
}}}

The error message is ignored. The main reason being that the form in
discarded in `FormView.form_invalid()`. Here's the current implementation
on master:

{{{#!python
def form_invalid(self, form):
"""
If the form is invalid, re-render the context data with the
data-filled form and errors.
"""
return self.render_to_response(self.get_context_data())
}}}

I proposed to modify this implementation to:

{{{#!python
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
}}}

since `Form.get_context_data()` is doing `kwargs.setdefault('form',
self.get_form())`. I did that on my view, but it does feel this is
something that belongs in Django.

Also, from my little understanding of the code, this also mean that if I
have a form like this:

{{{#!python
class MyForm(Form):
def clean_value(self):
value = self.cleaned_data['value']
try:
heavy_computation(value)
except ValueError as e:
raise ValidationError(e.message)
return value
}}}

The `heavy_computation()` is going run twice.

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

Django

unread,
Oct 12, 2015, 7:24:50 PM10/12/15
to django-...@googlegroups.com
#25548: Can't Form.add_error() in FormView.form_valid()
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: nobody
Type: Uncategorized | Status: new
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage:
FormView form_invalid | Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by acatton):

* needs_better_patch: => 0
* needs_tests: => 0
* needs_docs: => 0


Old description:

New description:

Let's consider this example:

{{{#!python
class MyView(FormView):
def form_valid(self, form):
value = form.cleaned_data['value']
try:
do_action(value)
except ValueError as e:
form.add_error(None, e.message)
return self.form_invalid(form)
return super().form_valid(form)
}}}

The error message is ignored. The main reason being that the form in
discarded in `FormView.form_invalid()`. Here's the current implementation
on master:

{{{#!python
def form_invalid(self, form):
"""
If the form is invalid, re-render the context data with the
data-filled form and errors.
"""
return self.render_to_response(self.get_context_data())
}}}

I propose to modify this implementation to:

{{{#!python
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
}}}

since `Form.get_context_data()` is doing `kwargs.setdefault('form',
self.get_form())`. I did that on my view, but it does feel this is
something that belongs in Django.

Also, from my little understanding of the code, this also mean that if I
have a form like this:

{{{#!python
class MyForm(Form):
def clean_value(self):
value = self.cleaned_data['value']
try:
heavy_computation(value)
except ValueError as e:
raise ValidationError(e.message)
return value
}}}

The `heavy_computation()` is going run twice.

--

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

Django

unread,
Oct 12, 2015, 7:31:48 PM10/12/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------

Reporter: acatton | Owner: nobody
Type: | Status: new
Cleanup/optimization |

Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |

Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0

Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by charettes):

* stage: Unreviewed => Accepted
* type: Uncategorized => Cleanup/optimization
* needs_tests: 0 => 1


Comment:

This makes a lot of sense.

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

Django

unread,
Oct 18, 2015, 5:10:21 AM10/18/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner:
Type: | Aristarhys
Cleanup/optimization | Status: assigned

Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Aristarhys):

* status: new => assigned
* owner: nobody => Aristarhys


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

Django

unread,
Oct 20, 2015, 2:36:58 PM10/20/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner:
Type: | Status: new
Cleanup/optimization |

Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Aristarhys):

* owner: Aristarhys =>
* status: assigned => new


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

Django

unread,
Oct 21, 2015, 8:33:55 AM10/21/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: assigned

Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by dudepare):

* status: new => assigned

* owner: => dudepare


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

Django

unread,
Nov 10, 2015, 3:20:11 AM11/10/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: assigned
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by alexmorozov):

@dudepare, if you don't mind, I can make a PR.

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:6>

Django

unread,
Nov 10, 2015, 5:27:05 AM11/10/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: assigned
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by dudepare):

Sure go ahead, I'm curious to see the unittest for this.

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:7>

Django

unread,
Nov 10, 2015, 8:13:40 AM11/10/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: assigned
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
FormView form_invalid |
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by alexmorozov):

https://github.com/django/django/pull/5620
@dudepare, you mean there should be something tricky with a unittest? I
feel like I've missed something big :).

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:8>

Django

unread,
Nov 10, 2015, 11:23:09 AM11/10/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: assigned
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin

Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1

Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by charettes):

* needs_better_patch: 0 => 1
* needs_tests: 1 => 0
* stage: Accepted => Ready for checkin


Comment:

Provided patch LGTM pending a small docstring rephrasing.

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:9>

Django

unread,
Nov 11, 2015, 1:40:42 AM11/11/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: assigned
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by alexmorozov):

@charettes, fixed.

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:10>

Django

unread,
Nov 11, 2015, 1:29:52 PM11/11/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: closed

Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution: fixed

Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette <charette.s@…>):

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


Comment:

In [changeset:"e171a83b1516a3a2a393a5300527af1aab21c213" e171a83]:
{{{
#!CommitTicketReference repository=""
revision="e171a83b1516a3a2a393a5300527af1aab21c213"
Fixed #25548 -- Prevented FormView.form_invalid() from discarding its form
argument.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:11>

Django

unread,
Dec 6, 2015, 2:42:45 PM12/6/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: closed
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution: fixed
Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by coagulant):

Could this be backported to upcoming 1.9.1 please? This is a fix for
regression in 1.9, so I hope this makes sense )

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:12>

Django

unread,
Dec 7, 2015, 8:12:34 AM12/7/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: closed
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution: fixed
Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by timgraham):

Yes, I'll backport now. I think the only reason it wasn't is that there's
no obvious indication that this is a regression (introduced in #24643).

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:13>

Django

unread,
Dec 7, 2015, 8:17:37 AM12/7/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: closed
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution: fixed
Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"0154702a987bd06d20e53fe23284b2c4a93b9063" 0154702a]:
{{{
#!CommitTicketReference repository=""
revision="0154702a987bd06d20e53fe23284b2c4a93b9063"
[1.9.x] Fixed #25548 -- Prevented FormView.form_invalid() from discarding
its form argument.

Backport of e171a83b1516a3a2a393a5300527af1aab21c213 from master
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:14>

Django

unread,
Dec 7, 2015, 8:21:00 AM12/7/15
to django-...@googlegroups.com
#25548: FormView.form_invalid() discards its form argument resulting in duplicated
validation
-------------------------------------+-------------------------------------
Reporter: acatton | Owner: dudepare
Type: | Status: closed
Cleanup/optimization |
Component: Generic views | Version: master
Severity: Normal | Resolution: fixed
Keywords: performance | Triage Stage: Ready for
FormView form_invalid | checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"285b08abc121fce878dbe536b0a68b421ec4300d" 285b08ab]:
{{{
#!CommitTicketReference repository=""
revision="285b08abc121fce878dbe536b0a68b421ec4300d"
Refs #25548 -- Forwardported 1.9.1 release note.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/25548#comment:15>

Reply all
Reply to author
Forward
0 new messages