@@ -126,19 +126,54 @@ model::
126126 form = UploadFileForm()
127127 return render(request, 'upload.html', {'form': form})
128128
129+ .. _uploading_multiple_files:
130+
129131Uploading multiple files
130132------------------------
131133
132- If you want to upload multiple files using one form field, set the ``multiple``
133- HTML attribute of field's widget:
134+ ..
135+ Tests in tests.forms_tests.field_tests.test_filefield.MultipleFileFieldTest
136+ should be updated after any changes in the following snippets.
137+
138+ If you want to upload multiple files using one form field, create a subclass
139+ of the field's widget and set the ``allow_multiple_selected`` attribute on it
140+ to ``True``.
141+
142+ In order for such files to be all validated by your form (and have the value of
143+ the field include them all), you will also have to subclass ``FileField``. See
144+ below for an example.
145+
146+ .. admonition:: Multiple file field
147+
148+ Django is likely to have a proper multiple file field support at some point
149+ in the future.
134150
135151.. code-block:: python
136152 :caption: ``forms.py``
137153
138154 from django import forms
139155
156+
157+ class MultipleFileInput(forms.ClearableFileInput):
158+ allow_multiple_selected = True
159+
160+
161+ class MultipleFileField(forms.FileField):
162+ def __init__(self, *args, **kwargs):
163+ kwargs.setdefault("widget", MultipleFileInput())
164+ super().__init__(*args, **kwargs)
165+
166+ def clean(self, data, initial=None):
167+ single_file_clean = super().clean
168+ if isinstance(data, (list, tuple)):
169+ result = [single_file_clean(d, initial) for d in data]
170+ else:
171+ result = single_file_clean(data, initial)
172+ return result
173+
174+
140175 class FileFieldForm(forms.Form):
141- file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}) )
176+ file_field = MultipleFileField( )
142177
143178Then override the ``post`` method of your
144179:class:`~django.views.generic.edit.FormView` subclass to handle multiple file
@@ -158,14 +193,32 @@ uploads:
158193 def post(self, request, *args, **kwargs):
159194 form_class = self.get_form_class()
160195 form = self.get_form(form_class)
161- files = request.FILES.getlist('file_field')
162196 if form.is_valid():
163- for f in files:
164- ... # Do something with each file.
165197 return self.form_valid(form)
166198 else:
167199 return self.form_invalid(form)
168200
201+ def form_valid(self, form):
202+ files = form.cleaned_data["file_field"]
203+ for f in files:
204+ ... # Do something with each file.
205+ return super().form_valid()
206+
207+ .. warning::
208+
209+ This will allow you to handle multiple files at the form level only. Be
210+ aware that you cannot use it to put multiple files on a single model
211+ instance (in a single field), for example, even if the custom widget is used
212+ with a form field related to a model ``FileField``.
213+
214+ .. versionchanged:: 3.2.19
215+
216+ In previous versions, there was no support for the ``allow_multiple_selected``
217+ class attribute, and users were advised to create the widget with the HTML
218+ attribute ``multiple`` set through the ``attrs`` argument. However, this
219+ caused validation of the form field to be applied only to the last file
220+ submitted, which could have adverse security implications.
221+
169222Upload Handlers
170223===============
171224
0 commit comments