summaryrefslogtreecommitdiff
path: root/django/forms
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2016-09-06 17:41:54 -0400
committerTim Graham <timograham@gmail.com>2016-09-22 13:07:23 -0400
commit0b59ea3343ef6f035064cfae1608f54c5a3fd147 (patch)
tree81a3499027dd1397d6345a518c4b4cba8e5a1cdd /django/forms
parent190cd0e49f967d2ec0b6c50a63f0d58d13319611 (diff)
[1.10.x] Fixed #27186 -- Fixed model form default fallback for MultiWidget, FileInput, SplitDateTimeWidget, SelectDateWidget, and SplitArrayWidget.
Thanks Matt Westcott for the review. Backport of 3507d4e773aa9ff2336e7230ba231c4ba6eb568f from master
Diffstat (limited to 'django/forms')
-rw-r--r--django/forms/models.py4
-rw-r--r--django/forms/widgets.py27
2 files changed, 25 insertions, 6 deletions
diff --git a/django/forms/models.py b/django/forms/models.py
index 1d54ea9676..ce93dead9e 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -54,8 +54,8 @@ def construct_instance(form, instance, fields=None, exclude=None):
continue
# Leave defaults for fields that aren't in POST data, except for
# checkbox inputs because they don't appear in POST data if not checked.
- if (f.has_default() and form.add_prefix(f.name) not in form.data and
- not getattr(form[f.name].field.widget, 'dont_use_model_field_default_for_empty_data', False)):
+ if (f.has_default() and
+ form[f.name].field.widget.value_omitted_from_data(form.data, form.files, form.add_prefix(f.name))):
continue
# Defer saving file-type fields until after the other fields, so a
# callable upload_to can use the values from other fields.
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 735207aa80..965f84f7df 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -237,6 +237,9 @@ class Widget(six.with_metaclass(RenameWidgetMethods)):
"""
return data.get(name)
+ def value_omitted_from_data(self, data, files, name):
+ return name not in data
+
def id_for_label(self, id_):
"""
Returns the HTML ID attribute of this Widget for use by a <label>,
@@ -350,6 +353,9 @@ class FileInput(Input):
"File widgets take data from FILES, not POST"
return files.get(name)
+ def value_omitted_from_data(self, data, files, name):
+ return name not in files
+
FILE_INPUT_CONTRADICTION = object()
@@ -480,10 +486,6 @@ def boolean_check(v):
class CheckboxInput(Widget):
- # Don't use model field defaults for fields that aren't in POST data,
- # because checkboxes don't appear in POST data if not checked.
- dont_use_model_field_default_for_empty_data = True
-
def __init__(self, attrs=None, check_test=None):
super(CheckboxInput, self).__init__(attrs)
# check_test is a callable that takes a value and returns True
@@ -511,6 +513,11 @@ class CheckboxInput(Widget):
value = values.get(value.lower(), value)
return bool(value)
+ def value_omitted_from_data(self, data, files, name):
+ # HTML checkboxes don't appear in POST data if not checked, so it's
+ # never known if the value is actually omitted.
+ return False
+
class Select(Widget):
allow_multiple_selected = False
@@ -871,6 +878,12 @@ class MultiWidget(Widget):
def value_from_datadict(self, data, files, name):
return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
+ def value_omitted_from_data(self, data, files, name):
+ return all(
+ widget.value_omitted_from_data(data, files, name + '_%s' % i)
+ for i, widget in enumerate(self.widgets)
+ )
+
def format_output(self, rendered_widgets):
"""
Given a list of rendered widgets (as strings), returns a Unicode string
@@ -1056,6 +1069,12 @@ class SelectDateWidget(Widget):
return '%s-%s-%s' % (y, m, d)
return data.get(name)
+ def value_omitted_from_data(self, data, files, name):
+ return not any(
+ ('{}_{}'.format(name, interval) in data)
+ for interval in ('year', 'month', 'day')
+ )
+
def create_select(self, name, field, value, val, choices, none_value):
if 'id' in self.attrs:
id_ = self.attrs['id']