Arbitrary Number of File Uploads in Django

536 Views Asked by At

What is the best way to allow a user to do an arbitrary number of file uploads with Django?

If I knew I was going to allow the user to do up to two file uploads then I could just do this in my forms.py...

from django import forms

class UploaderForm(forms.Form):
    file1 = forms.FileField(upload_to='user_files')
    file2 = forms.FileField(upload_to='user_files')

...and this in my views.py...

...
if request.method == 'POST':
    form = UploaderForm(request.POST)
    if form.is_valid():
        form.save()
        # do something.
else:
    form = UploaderForm()
...

However, I'm planning on using Javascript on the frontend to allow the user to continually add new <input type="file" name="fileN" /> elements (where N is the Nth file upload field added to the page.) The user can choose to do their upload with one or more files selected.

Is there any way that I can use Django's built in forms to accomplish this?

If, as I suspect, I can't utilize Django forms to generate the forms, can I use Django's validation? i.e., it would be handy to be able to access form.cleaned_data['file0'], form.cleaned_data['file1'], etc., instead of having to do my own validation.

Thanks.

1

There are 1 best solutions below

2
On BEST ANSWER

Formsets are exactly what you need.
http://docs.djangoproject.com/en/dev/topics/forms/formsets/#formsets

All you have to do is follow the field naming format that the formset uses 'form-0-field' in your javascript instead of fileN

Also modify the form-TOTAL_FORMS accordingly. Check the docs, they are especially thorough on this one.

class UploaderForm(forms.Form):
    file1 = forms.FileField(upload_to='user_files')


from django.forms.formsets import formset_factory
UploaderFormset = formset_factory(UploaderForm)

# long as you specify 'form-TOTAL_FORMS' and 2 other fields listed in the docs,
# the formset will auto generate form instances & populate with fields based on
# their 0 index.
formset = UploaderFormset(request.POST)

for form in formset.forms:
    form.save()

The best part is that this ties into validation perfectly, and you could even re-display your forms for error messages (which would be a bit of a pain if you were only generating html via ajax)