I was recently faced with the challenge of enabling directory upload in Django. For the most part that is easily done - HTML5 allows for a webkitdirectory attribute which expects a folder and then sends a list of files to the server, working exactly like multi-file upload, which Django handles easily. This would work for most use cases unless you are interested in preserving the directory structure on upload.

When a file is uploaded to Django, using the provided upload handlers, a TemporaryUploadedFile is created. It contains the file name, but not the file path. The information about the full directory tree is discarded by the upload handler.

The client has that information, so the only missing bit is how do we send it over to the server for processing. I ended up with a hidden form field called directories which is just a simple text field in the backend. Whenever there is a change in the directory upload field, a bit of JS fires up and populates the directories field with a JSON string representation of the directory tree where each file name is the key and its full path is the value. This is then submitted to the server as part of the upload form submission and can be processed. In my case I used it to create an archive of the upload that has the same structure as the uploaded folder.

<form method='POST' enctype="multipart/form-data">
    <input type="file" id="file_input" name="file_field" webkitdirectory directory/>
    <input type="text" id="directories" name="directories" hidden />
    <input type="submit"/>
</form>
<script>
 files = document.querySelector("#file_input").files;
 document.querySelector("#file_input").addEventListener("change", function() {
    files = document.querySelector("#file_input").files;
    var directories = {}
    for (var file of files) {
      file.webkitRelativePath
      directories[file.name] = file.webkitRelativePath
    }
    directories = JSON.stringify(directories);
    document.querySelector("#directories").value = directories
 });
</script>