/django-multiple-files

Simple Django project showing how to upload multiple files, WITHOUT JavaScript or Ajax.

MIT LicenseMIT

django-multiple-files

Simple project to upload multiple files with a Django form, WITHOUT JavaScript or Ajax.


Demonstrating how to link a model to a form, and how to return a human-readable filename whenever a model is printed:

### models.py
from django.db import models
import os

class fileentry(models.Model):
    file = models.FileField()
    uploaddate = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return os.path.basename(self.file.name)

This code is mostly unused; I haven't found a way to save individual form files from request.FILES yet. But having the code here demonstrates how to link a model to a form.


Enabling the multiple attribute in the form input, without having to manually display the form in the template:

### forms.py
from django import forms
from .models import fileentry

class fileform(forms.ModelForm):
    label = ''                      ### This hides the label next to the "Browse..." button
    class Meta:
        model = fileentry           ### Specify the model to connect to
        fields = ('file', )         ### This trailing comma is neccessary
        widgets = {
            'file':                 ### This is what allows you to select multiple files
                forms.ClearableFileInput(attrs={'multiple': True})}     

The trick here is looping over request.FILES.getlist('file'). Trying to loop over request.FILES only returns the last file.

### views.py
from django.shortcuts import render
from .forms import fileform

def upload(request):

    context = {'form': None, 'last': None}

    if request.method == 'POST':
        form = fileform(request.POST, request.FILES)
        if form.is_valid():                        ### Display a list of the last files uploaded
            context['last'] = '\n'.join([f.name for f in request.FILES.getlist('file')])
            
            for file in request.FILES.getlist('file'):
                print(file.name)
                with open("uploads/{}".format(file.name), 'wb+') as f:
                    for chunk in file.chunks():    ### Write in chunks; large files won't use a lot of RAM
                        f.write(chunk)
                  f.close()
                  
    else:
        form = fileform()

    context['form'] = form
    return render(request, 'upload/index.html', context)

What is important here is setting enctype="multipart/form-data".

### templates/upload/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Upload</title>
</head>
<body>

<p><strong><span>Files:</span></strong></p>
<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.file.errors }}
    {{ form.file }}
    <button type="submit">Upload</button>
</form>

<p><strong><span>Last upload:</span></strong></p>
<pre>{{ last }}</pre>

</body>
</html>