Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[1.0.X] Fixed #9587. Formset.is_valid() now returns True if an invali…

…d form is marked for deletion. Backport of r10206 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10219 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f7e52d449a62330a5c0e41fd4858a99039e6d605 1 parent 3543e12
@jkocherhans jkocherhans authored
Showing with 46 additions and 5 deletions.
  1. +17 −4 django/forms/formsets.py
  2. +29 −1 tests/regressiontests/forms/formsets.py
View
21 django/forms/formsets.py
@@ -4,7 +4,7 @@
from django.utils.translation import ugettext as _
from fields import IntegerField, BooleanField
from widgets import Media, HiddenInput
-from util import ErrorList, ValidationError
+from util import ErrorList, ErrorDict, ValidationError
__all__ = ('BaseFormSet', 'all_valid')
@@ -140,7 +140,7 @@ def _get_deleted_forms(self):
def _get_ordered_forms(self):
"""
Returns a list of form in the order specified by the incoming data.
- Raises an AttributeError if deletion is not allowed.
+ Raises an AttributeError if ordering is not allowed.
"""
if not self.is_valid() or not self.can_order:
raise AttributeError("'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__)
@@ -209,8 +209,21 @@ def is_valid(self):
# We loop over every form.errors here rather than short circuiting on the
# first failure to make sure validation gets triggered for every form.
forms_valid = True
- for errors in self.errors:
- if bool(errors):
+ for i in range(0, self._total_form_count):
+ form = self.forms[i]
+ if self.can_delete:
+ # The way we lookup the value of the deletion field here takes
+ # more code than we'd like, but the form's cleaned_data will
+ # not exist if the form is invalid.
+ field = form.fields[DELETION_FIELD_NAME]
+ prefix = form.add_prefix(DELETION_FIELD_NAME)
+ value = field.widget.value_from_datadict(self.data, self.files, prefix)
+ should_delete = field.clean(value)
+ if should_delete:
+ # This form is going to be deleted so any of its errors
+ # should not cause the entire formset to be invalid.
+ continue
+ if bool(self.errors[i]):
forms_valid = False
return forms_valid and not bool(self.non_form_errors())
View
30 tests/regressiontests/forms/formsets.py
@@ -241,7 +241,7 @@
# FormSets with deletion ######################################################
-We can easily add deletion ability to a FormSet with an agrument to
+We can easily add deletion ability to a FormSet with an argument to
formset_factory. This will add a boolean field to each form instance. When
that boolean field is True, the form will be in formset.deleted_forms
@@ -286,6 +286,34 @@
>>> [form.cleaned_data for form in formset.deleted_forms]
[{'votes': 900, 'DELETE': True, 'choice': u'Fergie'}]
+If we fill a form with something and then we check the can_delete checkbox for
+that form, that form's errors should not make the entire formset invalid since
+it's going to be deleted.
+
+>>> class CheckForm(Form):
+... field = IntegerField(min_value=100)
+
+>>> data = {
+... 'check-TOTAL_FORMS': '3', # the number of forms rendered
+... 'check-INITIAL_FORMS': '2', # the number of forms with initial data
+... 'check-0-field': '200',
+... 'check-0-DELETE': '',
+... 'check-1-field': '50',
+... 'check-1-DELETE': 'on',
+... 'check-2-field': '',
+... 'check-2-DELETE': '',
+... }
+>>> CheckFormSet = formset_factory(CheckForm, can_delete=True)
+>>> formset = CheckFormSet(data, prefix='check')
+>>> formset.is_valid()
+True
+
+If we remove the deletion flag now we will have our validation back.
+
+>>> data['check-1-DELETE'] = ''
+>>> formset = CheckFormSet(data, prefix='check')
+>>> formset.is_valid()
+False
# FormSets with ordering ######################################################

0 comments on commit f7e52d4

Please sign in to comment.
Something went wrong with that request. Please try again.