Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #9587. Formset.is_valid() now returns True if an invalid form i…

…s marked for deletion. Thanks for the test and intial patch, kratorius.

Note that this leaves the form and formset errors alone. Those forms still have errors, it's just that it doesn't matter that they're invalid in the context of the formset and deletion.
Also fixed #9665 while I was in there. Thanks, mark_hildreth.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10206 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 08056572e89a9ac1c958ef7d47efe576c76116da 1 parent 78cbc3a
Joseph Kocherhans authored March 30, 2009
21  django/forms/formsets.py
@@ -4,7 +4,7 @@
4 4
 from django.utils.translation import ugettext as _
5 5
 from fields import IntegerField, BooleanField
6 6
 from widgets import Media, HiddenInput
7  
-from util import ErrorList, ValidationError
  7
+from util import ErrorList, ErrorDict, ValidationError
8 8
 
9 9
 __all__ = ('BaseFormSet', 'all_valid')
10 10
 
@@ -152,7 +152,7 @@ def _get_deleted_forms(self):
152 152
     def _get_ordered_forms(self):
153 153
         """
154 154
         Returns a list of form in the order specified by the incoming data.
155  
-        Raises an AttributeError if deletion is not allowed.
  155
+        Raises an AttributeError if ordering is not allowed.
156 156
         """
157 157
         if not self.is_valid() or not self.can_order:
158 158
             raise AttributeError("'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__)
@@ -221,8 +221,21 @@ def is_valid(self):
221 221
         # We loop over every form.errors here rather than short circuiting on the
222 222
         # first failure to make sure validation gets triggered for every form.
223 223
         forms_valid = True
224  
-        for errors in self.errors:
225  
-            if bool(errors):
  224
+        for i in range(0, self.total_form_count()):
  225
+            form = self.forms[i]
  226
+            if self.can_delete:
  227
+                # The way we lookup the value of the deletion field here takes
  228
+                # more code than we'd like, but the form's cleaned_data will
  229
+                # not exist if the form is invalid.
  230
+                field = form.fields[DELETION_FIELD_NAME]
  231
+                prefix = form.add_prefix(DELETION_FIELD_NAME)
  232
+                value = field.widget.value_from_datadict(self.data, self.files, prefix)
  233
+                should_delete = field.clean(value)
  234
+                if should_delete:
  235
+                    # This form is going to be deleted so any of its errors
  236
+                    # should not cause the entire formset to be invalid.
  237
+                    continue
  238
+            if bool(self.errors[i]):
226 239
                 forms_valid = False
227 240
         return forms_valid and not bool(self.non_form_errors())
228 241
 
30  tests/regressiontests/forms/formsets.py
@@ -241,7 +241,7 @@
241 241
 
242 242
 # FormSets with deletion ######################################################
243 243
 
244  
-We can easily add deletion ability to a FormSet with an agrument to
  244
+We can easily add deletion ability to a FormSet with an argument to
245 245
 formset_factory. This will add a boolean field to each form instance. When
246 246
 that boolean field is True, the form will be in formset.deleted_forms
247 247
 
@@ -286,6 +286,34 @@
286 286
 >>> [form.cleaned_data for form in formset.deleted_forms]
287 287
 [{'votes': 900, 'DELETE': True, 'choice': u'Fergie'}]
288 288
 
  289
+If we fill a form with something and then we check the can_delete checkbox for
  290
+that form, that form's errors should not make the entire formset invalid since
  291
+it's going to be deleted.
  292
+
  293
+>>> class CheckForm(Form):
  294
+...    field = IntegerField(min_value=100)
  295
+
  296
+>>> data = {
  297
+...     'check-TOTAL_FORMS': '3', # the number of forms rendered
  298
+...     'check-INITIAL_FORMS': '2', # the number of forms with initial data
  299
+...     'check-0-field': '200',
  300
+...     'check-0-DELETE': '',
  301
+...     'check-1-field': '50',
  302
+...     'check-1-DELETE': 'on',
  303
+...     'check-2-field': '',
  304
+...     'check-2-DELETE': '',
  305
+... }
  306
+>>> CheckFormSet = formset_factory(CheckForm, can_delete=True)
  307
+>>> formset = CheckFormSet(data, prefix='check')
  308
+>>> formset.is_valid()
  309
+True
  310
+
  311
+If we remove the deletion flag now we will have our validation back.
  312
+
  313
+>>> data['check-1-DELETE'] = ''
  314
+>>> formset = CheckFormSet(data, prefix='check')
  315
+>>> formset.is_valid()
  316
+False
289 317
 
290 318
 # FormSets with ordering ######################################################
291 319
 

0 notes on commit 0805657

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