Code

Ticket #19997: formfields_empty_values.diff

File formfields_empty_values.diff, 13.6 KB (added by loic84, 16 months ago)
Line 
1diff --git a/django/forms/fields.py b/django/forms/fields.py
2index c7ed085..bc37701 100644
3--- a/django/forms/fields.py
4+++ b/django/forms/fields.py
5@@ -53,6 +53,7 @@ class Field(object):
6         'required': _('This field is required.'),
7         'invalid': _('Enter a valid value.'),
8     }
9+    empty_values = list(validators.EMPTY_VALUES)
10 
11     # Tracks each time a Field instance is created. Used to retain order.
12     creation_counter = 0
13@@ -125,11 +126,11 @@ class Field(object):
14         return value
15 
16     def validate(self, value):
17-        if value in validators.EMPTY_VALUES and self.required:
18+        if value in self.empty_values and self.required:
19             raise ValidationError(self.error_messages['required'])
20 
21     def run_validators(self, value):
22-        if value in validators.EMPTY_VALUES:
23+        if value in self.empty_values:
24             return
25         errors = []
26         for v in self.validators:
27@@ -210,7 +211,7 @@ class CharField(Field):
28 
29     def to_python(self, value):
30         "Returns a Unicode object."
31-        if value in validators.EMPTY_VALUES:
32+        if value in self.empty_values:
33             return ''
34         return smart_text(value)
35 
36@@ -244,7 +245,7 @@ class IntegerField(Field):
37         of int(). Returns None for empty values.
38         """
39         value = super(IntegerField, self).to_python(value)
40-        if value in validators.EMPTY_VALUES:
41+        if value in self.empty_values:
42             return None
43         if self.localize:
44             value = formats.sanitize_separators(value)
45@@ -275,7 +276,7 @@ class FloatField(IntegerField):
46         of float(). Returns None for empty values.
47         """
48         value = super(IntegerField, self).to_python(value)
49-        if value in validators.EMPTY_VALUES:
50+        if value in self.empty_values:
51             return None
52         if self.localize:
53             value = formats.sanitize_separators(value)
54@@ -311,7 +312,7 @@ class DecimalField(IntegerField):
55         than max_digits in the number, and no more than decimal_places digits
56         after the decimal point.
57         """
58-        if value in validators.EMPTY_VALUES:
59+        if value in self.empty_values:
60             return None
61         if self.localize:
62             value = formats.sanitize_separators(value)
63@@ -324,7 +325,7 @@ class DecimalField(IntegerField):
64 
65     def validate(self, value):
66         super(DecimalField, self).validate(value)
67-        if value in validators.EMPTY_VALUES:
68+        if value in self.empty_values:
69             return
70         # Check for NaN, Inf and -Inf values. We can't compare directly for NaN,
71         # since it is never equal to itself. However, NaN is the only value that
72@@ -401,7 +402,7 @@ class DateField(BaseTemporalField):
73         Validates that the input can be converted to a date. Returns a Python
74         datetime.date object.
75         """
76-        if value in validators.EMPTY_VALUES:
77+        if value in self.empty_values:
78             return None
79         if isinstance(value, datetime.datetime):
80             return value.date()
81@@ -425,7 +426,7 @@ class TimeField(BaseTemporalField):
82         Validates that the input can be converted to a time. Returns a Python
83         datetime.time object.
84         """
85-        if value in validators.EMPTY_VALUES:
86+        if value in self.empty_values:
87             return None
88         if isinstance(value, datetime.time):
89             return value
90@@ -451,7 +452,7 @@ class DateTimeField(BaseTemporalField):
91         Validates that the input can be converted to a datetime. Returns a
92         Python datetime.datetime object.
93         """
94-        if value in validators.EMPTY_VALUES:
95+        if value in self.empty_values:
96             return None
97         if isinstance(value, datetime.datetime):
98             return from_current_timezone(value)
99@@ -463,7 +464,7 @@ class DateTimeField(BaseTemporalField):
100             # components: date and time.
101             if len(value) != 2:
102                 raise ValidationError(self.error_messages['invalid'])
103-            if value[0] in validators.EMPTY_VALUES and value[1] in validators.EMPTY_VALUES:
104+            if value[0] in self.empty_values and value[1] in self.empty_values:
105                 return None
106             value = '%s %s' % tuple(value)
107         result = super(DateTimeField, self).to_python(value)
108@@ -531,7 +532,7 @@ class FileField(Field):
109         super(FileField, self).__init__(*args, **kwargs)
110 
111     def to_python(self, data):
112-        if data in validators.EMPTY_VALUES:
113+        if data in self.empty_values:
114             return None
115 
116         # UploadedFile objects should have name and size attributes.
117@@ -562,7 +563,7 @@ class FileField(Field):
118                 return False
119             # If the field is required, clearing is not possible (the widget
120             # shouldn't return False data in that case anyway). False is not
121-            # in validators.EMPTY_VALUES; if a False value makes it this far
122+            # in self.empty_value; if a False value makes it this far
123             # it should be validated from here on out as None (so it will be
124             # caught by the required check).
125             data = None
126@@ -763,7 +764,7 @@ class ChoiceField(Field):
127 
128     def to_python(self, value):
129         "Returns a Unicode object."
130-        if value in validators.EMPTY_VALUES:
131+        if value in self.empty_values:
132             return ''
133         return smart_text(value)
134 
135@@ -801,7 +802,7 @@ class TypedChoiceField(ChoiceField):
136         """
137         value = super(TypedChoiceField, self).to_python(value)
138         super(TypedChoiceField, self).validate(value)
139-        if value == self.empty_value or value in validators.EMPTY_VALUES:
140+        if value == self.empty_value or value in self.empty_values:
141             return self.empty_value
142         try:
143             value = self.coerce(value)
144@@ -864,7 +865,7 @@ class TypedMultipleChoiceField(MultipleChoiceField):
145         """
146         value = super(TypedMultipleChoiceField, self).to_python(value)
147         super(TypedMultipleChoiceField, self).validate(value)
148-        if value == self.empty_value or value in validators.EMPTY_VALUES:
149+        if value == self.empty_value or value in self.empty_values:
150             return self.empty_value
151         new_value = []
152         for choice in value:
153@@ -945,7 +946,7 @@ class MultiValueField(Field):
154         clean_data = []
155         errors = ErrorList()
156         if not value or isinstance(value, (list, tuple)):
157-            if not value or not [v for v in value if v not in validators.EMPTY_VALUES]:
158+            if not value or not [v for v in value if v not in self.empty_values]:
159                 if self.required:
160                     raise ValidationError(self.error_messages['required'])
161                 else:
162@@ -957,7 +958,7 @@ class MultiValueField(Field):
163                 field_value = value[i]
164             except IndexError:
165                 field_value = None
166-            if self.required and field_value in validators.EMPTY_VALUES:
167+            if self.required and field_value in self.empty_values:
168                 raise ValidationError(self.error_messages['required'])
169             try:
170                 clean_data.append(field.clean(field_value))
171@@ -1071,9 +1072,9 @@ class SplitDateTimeField(MultiValueField):
172         if data_list:
173             # Raise a validation error if time or date is empty
174             # (possible if SplitDateTimeField has required=False).
175-            if data_list[0] in validators.EMPTY_VALUES:
176+            if data_list[0] in self.empty_values:
177                 raise ValidationError(self.error_messages['invalid_date'])
178-            if data_list[1] in validators.EMPTY_VALUES:
179+            if data_list[1] in self.empty_values:
180                 raise ValidationError(self.error_messages['invalid_time'])
181             result = datetime.datetime.combine(*data_list)
182             return from_current_timezone(result)
183@@ -1087,7 +1088,7 @@ class IPAddressField(CharField):
184     default_validators = [validators.validate_ipv4_address]
185 
186     def to_python(self, value):
187-        if value in EMPTY_VALUES:
188+        if value in self.empty_values:
189             return ''
190         return value.strip()
191 
192@@ -1103,7 +1104,7 @@ class GenericIPAddressField(CharField):
193         super(GenericIPAddressField, self).__init__(*args, **kwargs)
194 
195     def to_python(self, value):
196-        if value in validators.EMPTY_VALUES:
197+        if value in self.empty_values:
198             return ''
199         value = value.strip()
200         if value and ':' in value:
201diff --git a/django/forms/models.py b/django/forms/models.py
202index 87fd546..7609bb7 100644
203--- a/django/forms/models.py
204+++ b/django/forms/models.py
205@@ -6,7 +6,6 @@ and database field objects.
206 from __future__ import absolute_import, unicode_literals
207 
208 from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, FieldError
209-from django.core.validators import EMPTY_VALUES
210 from django.forms.fields import Field, ChoiceField
211 from django.forms.forms import BaseForm, get_declared_fields
212 from django.forms.formsets import BaseFormSet, formset_factory
213@@ -301,7 +300,7 @@ class BaseModelForm(BaseForm):
214             else:
215                 form_field = self.fields[field]
216                 field_value = self.cleaned_data.get(field, None)
217-                if not f.blank and not form_field.required and field_value in EMPTY_VALUES:
218+                if not f.blank and not form_field.required and field_value in form_field.empty_values:
219                     exclude.append(f.name)
220         return exclude
221 
222@@ -880,7 +879,7 @@ class InlineForeignKeyField(Field):
223         super(InlineForeignKeyField, self).__init__(*args, **kwargs)
224 
225     def clean(self, value):
226-        if value in EMPTY_VALUES:
227+        if value in self.empty_values:
228             if self.pk_field:
229                 return None
230             # if there is no value act as we did before.
231@@ -1000,7 +999,7 @@ class ModelChoiceField(ChoiceField):
232         return super(ModelChoiceField, self).prepare_value(value)
233 
234     def to_python(self, value):
235-        if value in EMPTY_VALUES:
236+        if value in self.empty_values:
237             return None
238         try:
239             key = self.to_field_name or 'pk'
240diff --git a/django/test/testcases.py b/django/test/testcases.py
241index 345e4b1..44ddb62 100644
242--- a/django/test/testcases.py
243+++ b/django/test/testcases.py
244@@ -27,7 +27,6 @@ from django.core.management.color import no_style
245 from django.core.servers.basehttp import (WSGIRequestHandler, WSGIServer,
246     WSGIServerException)
247 from django.core.urlresolvers import clear_url_caches
248-from django.core.validators import EMPTY_VALUES
249 from django.db import connection, connections, DEFAULT_DB_ALIAS, transaction
250 from django.forms.fields import CharField
251 from django.http import QueryDict
252@@ -322,7 +321,7 @@ class SimpleTestCase(ut2.TestCase):
253                     raised error messages.
254             field_args: the args passed to instantiate the field
255             field_kwargs: the kwargs passed to instantiate the field
256-            empty_value: the expected clean output for inputs in EMPTY_VALUES
257+            empty_value: the expected clean output for inputs in empty_values
258 
259         """
260         if field_args is None:
261@@ -347,7 +346,7 @@ class SimpleTestCase(ut2.TestCase):
262             self.assertEqual(context_manager.exception.messages, errors)
263         # test required inputs
264         error_required = [force_text(required.error_messages['required'])]
265-        for e in EMPTY_VALUES:
266+        for e in required.empty_values:
267             with self.assertRaises(ValidationError) as context_manager:
268                 required.clean(e)
269             self.assertEqual(context_manager.exception.messages,
270diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt
271index 3b2babd..b917086 100644
272--- a/docs/topics/testing/overview.txt
273+++ b/docs/topics/testing/overview.txt
274@@ -1480,7 +1480,7 @@ your test suite.
275         error messages.
276     :param field_args: the args passed to instantiate the field.
277     :param field_kwargs: the kwargs passed to instantiate the field.
278-    :param empty_value: the expected clean output for inputs in ``EMPTY_VALUES``.
279+    :param empty_value: the expected clean output for inputs in ``empty_values``.
280 
281     For example, the following code tests that an ``EmailField`` accepts
282     "a@a.com" as a valid email address, but rejects "aaa" with a reasonable
283diff --git a/tests/forms_tests/tests/forms.py b/tests/forms_tests/tests/forms.py
284index f856e30..1f65045 100644
285--- a/tests/forms_tests/tests/forms.py
286+++ b/tests/forms_tests/tests/forms.py
287@@ -1797,3 +1797,32 @@ class FormsTestCase(TestCase):
288         form = NameForm(data={'name' : ['fname', 'lname']})
289         self.assertTrue(form.is_valid())
290         self.assertEqual(form.cleaned_data, {'name' : 'fname lname'})
291+
292+    def test_empty_values(self):
293+        class OldFakeJSONField(forms.Field):
294+            def to_python(self, value):
295+                if value in [None, '']:
296+                    return None
297+                # Fake json.loads.
298+                if value == '{}':
299+                    return {}
300+                raise NotImplementedError
301+
302+            def prepare_value(self, value):
303+                if value in [None, '']:
304+                    return ''
305+                # Fake json.dumps
306+                if value == {}:
307+                    return '{}'
308+                raise NotImplementedError
309+
310+        class NewFakeJSONField(OldFakeJSONField):
311+            empty_values = [None, '']
312+
313+        class FakeJSONForm(forms.Form):
314+            old = OldFakeJSONField()
315+            new = NewFakeJSONField()
316+        form = FakeJSONForm(data={'old': '{}', 'new': '{}'});
317+        form.full_clean()
318+        self.assertEqual(form.errors, {'old': ['This field is required.']})
319+        self.assertEqual(form.cleaned_data, {'new' : {}})