From f59a2e84f00b1b33eef8c3ed48e06a8548364998 Mon Sep 17 00:00:00 2001 From: Todd Dembrey <todd.dembrey@torchbox.com> Date: Tue, 25 Sep 2018 11:36:07 +0100 Subject: [PATCH] Totally rework how the multifile upload works --- opentech/apply/stream_forms/fields.py | 55 ++++++++++++++++--- .../stream_forms/fields/multi_file_field.html | 13 +++++ 2 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 opentech/apply/stream_forms/templates/stream_forms/fields/multi_file_field.html diff --git a/opentech/apply/stream_forms/fields.py b/opentech/apply/stream_forms/fields.py index 7517213d0..b2b0f44fa 100644 --- a/opentech/apply/stream_forms/fields.py +++ b/opentech/apply/stream_forms/fields.py @@ -1,25 +1,64 @@ -from django.forms import FileInput, FileField +from django.forms import ClearableFileInput, FileField, CheckboxInput -class MultiFileInput(FileInput): +class MultiFileInput(ClearableFileInput): """ File Input only returns one file from its clean method. This passes all files through the clean method and means we have a list of files available for post processing """ - def __init__(self, *args, attrs={}, **kwargs): - attrs['multiple'] = True - super().__init__(*args, attrs=attrs, **kwargs) + template_name = 'stream_forms/fields/multi_file_field.html' + + input_text = '' + + def __init__(self, *args, **kwargs): + self.multiple = kwargs.pop('multiple', True) + super().__init__(*args, **kwargs) + + def is_initial(self, value): + is_initial = super().is_initial + return all( + is_initial(file) for file in value + ) + + def render(self, name, value, attrs=None): + if self.multiple: + attrs['multiple'] = 'multiple' + + return super().render(name, value, attrs) def value_from_datadict(self, data, files, name): - return files.getlist(name) + if hasattr(files, 'getlist'): + upload = files.getlist(name) + else: + upload = files.get(name) + if not isinstance(upload, list): + upload = [upload] + + checkbox_name = self.clear_checkbox_name(name) + checkboxes = {k for k in data if checkbox_name in k} + cleared = { + i for i, checkbox in enumerate(checkboxes) + if CheckboxInput().value_from_datadict(data, files, checkbox) + } + + return { + 'files': upload, + 'cleared': cleared, + } class MultiFileField(FileField): widget = MultiFileInput def clean(self, value, initial): - if not value: + files = value['files'] + cleared = value['cleared'] + if not files and not cleared: return initial - return [FileField().clean(file, initial) for file in value] + new = [FileField().clean(file, initial) for file in files] + + old = [file for i, file in enumerate(initial) if i not in cleared] + + return old + new diff --git a/opentech/apply/stream_forms/templates/stream_forms/fields/multi_file_field.html b/opentech/apply/stream_forms/templates/stream_forms/fields/multi_file_field.html new file mode 100644 index 000000000..de6bbcfaf --- /dev/null +++ b/opentech/apply/stream_forms/templates/stream_forms/fields/multi_file_field.html @@ -0,0 +1,13 @@ +{% if widget.is_initial %}{{ widget.initial_text }}: +<p> +{{ widget.clear_checkbox_label }} +</p> +{% for file in widget.value %} +<p> +<input type="checkbox" name="{{ widget.checkbox_name }}-{{ forloop.counter }}" id="{{ widget.checkbox_id }}-{{ forloop.counter }}"> +<label for="{{ widget.checkbox_id }}-{{ forloop.counter }}"></label> +<a href="{{ file.url }}">{{ file.filename }}</a> +</p> +{% endfor %} +{{ widget.input_text }}{% endif %} +<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> -- GitLab