@@ -144,22 +144,54 @@ a :class:`~django.core.files.File` like object to the
144
144
instance = ModelWithFileField(file_field=content_file)
145
145
instance.save()
146
146
147
+ .. _uploading_multiple_files:
148
+
147
149
Uploading multiple files
148
150
------------------------
149
151
150
- If you want to upload multiple files using one form field, set the ``multiple``
151
- HTML attribute of field's widget:
152
+ ..
153
+ Tests in tests.forms_tests.field_tests.test_filefield.MultipleFileFieldTest
154
+ should be updated after any changes in the following snippets.
155
+
156
+ If you want to upload multiple files using one form field, create a subclass
157
+ of the field's widget and set the ``allow_multiple_selected`` attribute on it
158
+ to ``True``.
159
+
160
+ In order for such files to be all validated by your form (and have the value of
161
+ the field include them all), you will also have to subclass ``FileField``. See
162
+ below for an example.
163
+
164
+ .. admonition:: Multiple file field
165
+
166
+ Django is likely to have a proper multiple file field support at some point
167
+ in the future.
152
168
153
169
.. code-block:: python
154
170
:caption: ``forms.py``
155
171
156
172
from django import forms
157
173
158
174
175
+ class MultipleFileInput(forms.ClearableFileInput):
176
+ allow_multiple_selected = True
177
+
178
+
179
+ class MultipleFileField(forms.FileField):
180
+ def __init__(self, *args, **kwargs):
181
+ kwargs.setdefault("widget", MultipleFileInput())
182
+ super().__init__(*args, **kwargs)
183
+
184
+ def clean(self, data, initial=None):
185
+ single_file_clean = super().clean
186
+ if isinstance(data, (list, tuple)):
187
+ result = [single_file_clean(d, initial) for d in data]
188
+ else:
189
+ result = single_file_clean(data, initial)
190
+ return result
191
+
192
+
159
193
class FileFieldForm(forms.Form):
160
- file_field = forms.FileField(
161
- widget=forms.ClearableFileInput(attrs={"multiple": True})
162
- )
194
+ file_field = MultipleFileField()
163
195
164
196
Then override the ``post`` method of your
165
197
:class:`~django.views.generic.edit.FormView` subclass to handle multiple file
@@ -180,14 +212,32 @@ uploads:
180
212
def post(self, request, *args, **kwargs):
181
213
form_class = self.get_form_class()
182
214
form = self.get_form(form_class)
183
- files = request.FILES.getlist("file_field")
184
215
if form.is_valid():
185
- for f in files:
186
- ... # Do something with each file.
187
216
return self.form_valid(form)
188
217
else:
189
218
return self.form_invalid(form)
190
219
220
+ def form_valid(self, form):
221
+ files = form.cleaned_data["file_field"]
222
+ for f in files:
223
+ ... # Do something with each file.
224
+ return super().form_valid()
225
+
226
+ .. warning::
227
+
228
+ This will allow you to handle multiple files at the form level only. Be
229
+ aware that you cannot use it to put multiple files on a single model
230
+ instance (in a single field), for example, even if the custom widget is used
231
+ with a form field related to a model ``FileField``.
232
+
233
+ .. versionchanged:: 3.2.19
234
+
235
+ In previous versions, there was no support for the ``allow_multiple_selected``
236
+ class attribute, and users were advised to create the widget with the HTML
237
+ attribute ``multiple`` set through the ``attrs`` argument. However, this
238
+ caused validation of the form field to be applied only to the last file
239
+ submitted, which could have adverse security implications.
240
+
191
241
Upload Handlers
192
242
===============
193
243
0 commit comments