Code

Ticket #6033: is_empty_clean_field.4.diff

File is_empty_clean_field.4.diff, 5.7 KB (added by Øyvind Saltvik <oyvind@…>, 6 years ago)

This one actually works

Line 
1Index: django/newforms/formsets.py
2===================================================================
3--- django/newforms/formsets.py (revision 6777)
4+++ django/newforms/formsets.py (working copy)
5@@ -116,14 +116,19 @@
6         self.deleted_data = []
7         # Process change forms
8         for form in self.change_forms:
9-            if form.is_valid():
10+            if form.is_bound:
11+                form.full_clean(keep_invalid=True)
12+            if hasattr(form, 'cleaned_data'):
13                 if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]:
14                     self.deleted_data.append(form.cleaned_data)
15+                elif form.is_valid():
16+                    self.cleaned_data.append(form.cleaned_data)
17                 else:
18-                    self.cleaned_data.append(form.cleaned_data)
19+                    self._is_valid = False
20+                    errors.append(form.errors)
21             else:
22-                self._is_valid = False
23-            errors.append(form.errors)
24+                self._is_valid = False       
25+                errors.append(form.errors)
26         # Process add forms in reverse so we can easily tell when the remaining
27         # ones should be required.
28         reamining_forms_required = False
29@@ -168,6 +173,20 @@
30         """
31         return self.cleaned_data
32 
33+    def clean_field(self, form, f):
34+        if f in form.fields:
35+            field = form.fields.get(f)
36+            value = field.widget.value_from_datadict(self.data, self.files, '%s-%s' % (form.prefix, f))
37+            try:
38+                value = field.clean(value)
39+                if hasattr(self, 'clean_%s' % f):
40+                    value = getattr(self, 'clean_%s' % f)()
41+            except ValidationError, e:
42+                return False
43+            return value
44+        else:
45+            return False
46+               
47     def add_fields(self, form, index):
48         """A hook for adding extra fields on to each form instance."""
49         if self.orderable:
50Index: django/newforms/models.py
51===================================================================
52--- django/newforms/models.py   (revision 6777)
53+++ django/newforms/models.py   (working copy)
54@@ -310,10 +310,10 @@
55             existing_objects[obj._get_pk_val()] = obj
56         saved_instances = []
57         for form in self.change_forms:
58-            obj = existing_objects[form.cleaned_data[self.model._meta.pk.attname]]
59-            if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]:
60+            obj = existing_objects[self.clean_field(form, self.model._meta.pk.attname)]
61+            if self.deletable and self.clean_field(form, DELETION_FIELD_NAME):
62                 obj.delete()
63-            else:
64+            elif self.is_valid():
65                 saved_instances.append(self.save_instance(form, obj, commit=commit))
66         return saved_instances
67 
68@@ -325,9 +325,10 @@
69             # If someone has marked an add form for deletion, don't save the
70             # object. At some point it would be nice if we didn't display
71             # the deletion widget for add forms.
72-            if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]:
73+            if self.deletable and self.clean_field(form, DELETION_FIELD_NAME):
74                 continue
75-            new_objects.append(self.save_new(form, commit=commit))
76+            if self.is_valid():
77+                new_objects.append(self.save_new(form, commit=commit))
78         return new_objects
79 
80     def add_fields(self, form, index):
81Index: django/newforms/forms.py
82===================================================================
83--- django/newforms/forms.py    (revision 6777)
84+++ django/newforms/forms.py    (working copy)
85@@ -191,7 +191,7 @@
86                 return False
87         return True
88 
89-    def full_clean(self):
90+    def full_clean(self, keep_invalid=False):
91         """
92         Cleans all of self.data and populates self._errors and
93         self.cleaned_data.
94@@ -219,7 +219,7 @@
95             self.cleaned_data = self.clean()
96         except ValidationError, e:
97             self._errors[NON_FIELD_ERRORS] = e.messages
98-        if self._errors:
99+        if not keep_invalid and self._errors:
100             delattr(self, 'cleaned_data')
101 
102     def clean(self):
103Index: tests/regressiontests/forms/widgets.py
104===================================================================
105--- tests/regressiontests/forms/widgets.py      (revision 6777)
106+++ tests/regressiontests/forms/widgets.py      (working copy)
107@@ -292,6 +292,12 @@
108 >>> w.value_from_datadict({}, {}, 'testing')
109 False
110 
111+The CheckboxInput widget will always be empty when there is a False value
112+>>> w.is_empty(False)
113+True
114+>>> w.is_empty(True)
115+False
116+
117 # Select Widget ###############################################################
118 
119 >>> w = Select()
120@@ -453,6 +459,15 @@
121 <option value="3" selected="selected">No</option>
122 </select>
123 
124+The NullBooleanSelect widget will always be empty when Unknown or No is selected
125+as its value.  This is to stay compliant with the CheckboxInput behavior
126+>>> w.is_empty(False)
127+True
128+>>> w.is_empty(None)
129+True
130+>>> w.is_empty(True)
131+False
132+
133 """ + \
134 r""" # [This concatenation is to keep the string below the jython's 32K limit].
135 # SelectMultiple Widget #######################################################
136@@ -895,6 +910,16 @@
137 >>> w.render('name', ['john', 'lennon'])
138 u'<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />'
139 
140+The MultiWidget will be empty only when all widgets are considered empty.
141+>>> w.is_empty(['john', 'lennon'])
142+False
143+>>> w.is_empty(['john', ''])
144+False
145+>>> w.is_empty(['', ''])
146+True
147+>>> w.is_empty([None, None])
148+True
149+
150 # SplitDateTimeWidget #########################################################
151 
152 >>> w = SplitDateTimeWidget()