@@ -144,22 +144,54 @@ a :class:`~django.core.files.File` like object to the
144144 instance = ModelWithFileField(file_field=content_file)
145145 instance.save()
146146
147+ .. _uploading_multiple_files:
148+
147149Uploading multiple files
148150------------------------
149151
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.
152168
153169.. code-block:: python
154170 :caption: ``forms.py``
155171
156172 from django import forms
157173
158174
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+
159193 class FileFieldForm(forms.Form):
160- file_field = forms.FileField(
161- widget=forms.ClearableFileInput(attrs={"multiple": True})
162- )
194+ file_field = MultipleFileField()
163195
164196Then override the ``post`` method of your
165197:class:`~django.views.generic.edit.FormView` subclass to handle multiple file
@@ -180,14 +212,32 @@ uploads:
180212 def post(self, request, *args, **kwargs):
181213 form_class = self.get_form_class()
182214 form = self.get_form(form_class)
183- files = request.FILES.getlist("file_field")
184215 if form.is_valid():
185- for f in files:
186- ... # Do something with each file.
187216 return self.form_valid(form)
188217 else:
189218 return self.form_invalid(form)
190219
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+
191241Upload Handlers
192242===============
193243
0 commit comments