diff options
| author | Tim Graham <timograham@gmail.com> | 2016-09-06 17:41:54 -0400 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2016-09-22 12:20:58 -0400 |
| commit | 3507d4e773aa9ff2336e7230ba231c4ba6eb568f (patch) | |
| tree | 09467b4724131e91b0afe1d2f133e5e56ba068cf /django/forms | |
| parent | 92323d54fd6df077dc523c423c7bb2dd8dbde621 (diff) | |
Fixed #27186 -- Fixed model form default fallback for MultiWidget, FileInput, SplitDateTimeWidget, SelectDateWidget, and SplitArrayWidget.
Thanks Matt Westcott for the review.
Diffstat (limited to 'django/forms')
| -rw-r--r-- | django/forms/models.py | 4 | ||||
| -rw-r--r-- | django/forms/widgets.py | 27 |
2 files changed, 25 insertions, 6 deletions
diff --git a/django/forms/models.py b/django/forms/models.py index f44ce33f65..3fadc2e3b5 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 4ed9c67ff2..f9cfaee9f9 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -236,6 +236,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>, @@ -351,6 +354,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() @@ -481,10 +487,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 @@ -510,6 +512,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 @@ -876,6 +883,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 @@ -1061,6 +1074,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'] |
