Code

Ticket #5828: 6614_is_empty_fix.diff

File 6614_is_empty_fix.diff, 4.5 KB (added by brosner, 7 years ago)

adds an is_empty to widget classes w/tests.

Line 
1=== django/newforms/forms.py
2==================================================================
3--- django/newforms/forms.py    (revision 88)
4+++ django/newforms/forms.py    (local)
5@@ -189,12 +189,11 @@
6         for name, field in self.fields.items():
7             if name in exceptions:
8                 continue
9-            # value_from_datadict() gets the data from the dictionary.
10+            # value_from_datadict() gets the data from the data dictionaries.
11             # Each widget type knows how to retrieve its own data, because some
12             # widgets split data over several HTML fields.
13             value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
14-            # HACK: ['', ''] and [None, None] deal with SplitDateTimeWidget. This should be more robust.
15-            if value not in (None, '', ['', ''], [None, None]):
16+            if not field.widget.is_empty(value):
17                 return False
18         return True
19 
20=== django/newforms/widgets.py
21==================================================================
22--- django/newforms/widgets.py  (revision 88)
23+++ django/newforms/widgets.py  (local)
24@@ -164,6 +164,15 @@
25         of this widget. Returns None if it's not provided.
26         """
27         return data.get(name, None)
28+   
29+    def is_empty(self, value):
30+        """
31+        Given a dictionary of data and this widget's name, return True if the
32+        widget data is empty or False when not empty.
33+        """
34+        if value not in (None, ''):
35+            return False
36+        return True
37 
38     def id_for_label(self, id_):
39         """
40@@ -294,6 +303,11 @@
41             # send results for unselected checkboxes.
42             return False
43         return super(CheckboxInput, self).value_from_datadict(data, files, name)
44+   
45+    def is_empty(self, value):
46+        # this widget will always either be True or False, so always return the
47+        # opposite value so False values will make the form empty
48+        return not value
49 
50 class Select(Widget):
51     def __init__(self, attrs=None, choices=()):
52@@ -333,6 +347,12 @@
53     def value_from_datadict(self, data, files, name):
54         value = data.get(name, None)
55         return {u'2': True, u'3': False, True: True, False: False}.get(value, None)
56+   
57+    def is_empty(self, value):
58+        # this widget will always either be True, False or None, so always
59+        # return the opposite value so False and None values will make the
60+        # form empty.
61+        return not value
62 
63 class SelectMultiple(Widget):
64     def __init__(self, attrs=None, choices=()):
65@@ -521,6 +541,12 @@
66 
67     def value_from_datadict(self, data, files, name):
68         return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
69+   
70+    def is_empty(self, value):
71+        for widget, val in zip(self.widgets, value):
72+            if not widget.is_empty(val):
73+                return False
74+        return True
75 
76     def format_output(self, rendered_widgets):
77         """
78=== tests/regressiontests/forms/widgets.py
79==================================================================
80--- tests/regressiontests/forms/widgets.py      (revision 88)
81+++ tests/regressiontests/forms/widgets.py      (local)
82@@ -282,6 +282,12 @@
83 >>> w.value_from_datadict({}, {}, 'testing')
84 False
85 
86+The CheckboxInput widget will always be empty when there is a False value
87+>>> w.is_empty(False)
88+True
89+>>> w.is_empty(True)
90+False
91+
92 # Select Widget ###############################################################
93 
94 >>> w = Select()
95@@ -432,6 +438,15 @@
96 <option value="3" selected="selected">No</option>
97 </select>
98 
99+The NullBooleanSelect widget will always be empty when Unknown or No is selected
100+as its value.  This is to stay compliant with the CheckboxInput behavior
101+>>> w.is_empty(False)
102+True
103+>>> w.is_empty(None)
104+True
105+>>> w.is_empty(True)
106+False
107+
108 """ + \
109 r""" # [This concatenation is to keep the string below the jython's 32K limit].
110 # SelectMultiple Widget #######################################################
111@@ -834,6 +849,16 @@
112 >>> w.render('name', ['john', 'lennon'])
113 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" />'
114 
115+The MultiWidget will be empty only when all widgets are considered empty.
116+>>> w.is_empty(['john', 'lennon'])
117+False
118+>>> w.is_empty(['john', ''])
119+False
120+>>> w.is_empty(['', ''])
121+True
122+>>> w.is_empty([None, None])
123+True
124+
125 # SplitDateTimeWidget #########################################################
126 
127 >>> w = SplitDateTimeWidget()