Skip to content
Snippets Groups Projects
Unverified Commit bef1538a authored by Fredrik Jonsson's avatar Fredrik Jonsson Committed by GitHub
Browse files

Merge pull request #616 from OpenTechFund/bugfix/!544-missing-files-on-page

Bugfix/#544 missing files on page
parents d5a78d67 65f20f99
No related branches found
No related tags found
No related merge requests found
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. 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 This passes all files through the clean method and means we have a list of
files available for post processing files available for post processing
""" """
def __init__(self, *args, attrs={}, **kwargs): template_name = 'stream_forms/fields/multi_file_field.html'
attrs['multiple'] = True
super().__init__(*args, attrs=attrs, **kwargs) 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=dict()):
if self.multiple:
attrs['multiple'] = 'multiple'
return super().render(name, value, attrs)
def value_from_datadict(self, data, files, name): 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 = {
int(checkbox.replace(checkbox_name, '')) for checkbox in checkboxes
if CheckboxInput().value_from_datadict(data, files, checkbox)
}
return {
'files': upload,
'cleared': cleared,
}
class MultiFileField(FileField): class MultiFileField(FileField):
widget = MultiFileInput widget = MultiFileInput
def clean(self, value, initial): def clean(self, value, initial):
if not value: files = value['files']
cleared = value['cleared']
if not files and not cleared:
return initial return initial
return [FileField().clean(file, initial) for file in value] new = [FileField().clean(file, initial) for file in files]
if initial:
old = [file for i, file in enumerate(initial) if i not in cleared]
else:
old = []
return old + new
...@@ -22,8 +22,15 @@ class StreamFieldFile(File): ...@@ -22,8 +22,15 @@ class StreamFieldFile(File):
self.filename = filename or os.path.basename(self.name) self.filename = filename or os.path.basename(self.name)
self._committed = False self._committed = False
def __str__(self):
return self.filename
def __eq__(self, other): def __eq__(self, other):
return self.filename == other.filename and self.size == other.size if isinstance(other, File):
return self.filename == other.filename and self.size == other.size
# Rely on the other object to know how to check equality
# Could cause infinite loop if the other object is unsure how to compare
return other.__eq__(self)
def _get_file(self): def _get_file(self):
if getattr(self, '_file', None) is None: if getattr(self, '_file', None) is None:
......
{% if widget.is_initial %}{{ widget.initial_text }}:
<p>
{{ widget.clear_checkbox_label }}
</p>
{% for file in widget.value %}
<p>
{% with y=forloop.counter0|stringformat:"s" %}
{% with file_id=widget.checkbox_name|add:'-'|add:y %}
<input type="checkbox" name="{{ file_id }}" id="{{ file_id }}">
<label for="{{ file_id }}"></label>
{% endwith %}
{% endwith %}
<a href="{{ file.url }}">{{ file }}</a>
</p>
{% endfor %}
{{ widget.input_text }}{% endif %}
<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
# from django.test import TestCase from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
# Create your tests here. from faker import Faker
from .files import StreamFieldFile
from .fields import MultiFileField, MultiFileInput
fake = Faker()
def make_files(number):
file_names = [f'{fake.word()}_{i}' for i in range(3)]
files = [
StreamFieldFile(SimpleUploadedFile(name, b'Some File Content'), filename=name)
for name in file_names
]
return files
class TestMultiFileInput(TestCase):
widget = MultiFileInput()
def test_renders_multiple_attr(self):
html = self.widget.render('', [])
self.assertIn('multiple', html)
def test_renders_multiple_files(self):
files = make_files(3)
html = self.widget.render('', files)
for file in files:
self.assertIn(file.filename, html)
def test_handles_files(self):
field_name = 'testing'
files = make_files(3)
files_data = {field_name: files}
data = self.widget.value_from_datadict({}, files_data, field_name)
self.assertEqual(data['files'], files)
def test_no_delete(self):
data = self.widget.value_from_datadict({}, {}, '')
self.assertFalse(data['cleared'])
def test_delete(self):
field_name = 'testing'
field_id = self.widget.clear_checkbox_name(field_name) + '-'
form_data = {
field_id + '0': 'on',
field_id + '4': 'on',
}
data = self.widget.value_from_datadict(form_data, {}, field_name)
self.assertEqual(data['cleared'], {0, 4})
class TestMultiFileField(TestCase):
field = MultiFileField()
def multi_file_value(self, files=list(), cleared=set()):
return {
'files': files,
'cleared': cleared,
}
def test_returns_files_if_no_change(self):
files = make_files(3)
cleaned = self.field.clean(self.multi_file_value(), files)
self.assertEqual(files, cleaned)
def test_returns_new_files(self):
files = make_files(3)
cleaned = self.field.clean(self.multi_file_value(files=files), None)
self.assertEqual(files, cleaned)
def test_returns_inital_and_files(self):
initial_files = make_files(3)
new_files = make_files(3)
cleaned = self.field.clean(self.multi_file_value(files=new_files), initial_files)
self.assertEqual(initial_files + new_files, cleaned)
def test_returns_nothing_all_cleared(self):
initial_files = make_files(3)
cleaned = self.field.clean(self.multi_file_value(cleared=range(3)), initial_files)
self.assertEqual([], cleaned)
def test_returns_something_some_cleared(self):
initial_files = make_files(3)
cleaned = self.field.clean(self.multi_file_value(cleared=[0, 2]), initial_files)
self.assertEqual([initial_files[1]], cleaned)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment