Search code examples
jquerypython-2.7bottleform-data

How to handle multiple file uploads where the name and number of inputs is dynamic?


I am uploading multiple images through file inputs where the name and number of inputs is dynamic.

They do follow this naming convention however:

<input name = "image_path" ...
<input name = "image_path_F1" ...
<input name = "image_path_F2" ...
<input name = "image_path_F3" ...

The inputs are sent as FormData objects.

When handling a single image from the Python scripts I have previously used:

uploaded_image = request.files.name_of_file_input_here

Question

Is there a generic 'catch all' type of method available with request.files which could be used like:

uploaded_images = request.files.*all

Or will I need to create some sort of loop to handle the possible file names eg:

Client Side (jQuery)

var names_array = ["image_path","image_path_F1","image_path_F2"];
var length_of_names_array = 3;

sent to Python...

Python

names_array = request.forms.names_array
length_of_names_array = request.forms.length_of_names_array

counter = 1
for i, val in enumerate(range(length_of_names_array)):
    if i == 0:
        constructor = "image_path"
        request.files.constructor
    else:
        constructor = "image_path_F" + str(counter)
        request.files.constructor
        counter += 1

The above code will just generate the correct names (and actually I'm not sure if the request.files method above would work with constructor - edit, it doesn't seem to).

There may be a solution to be found in the approach here:

https://stackoverflow.com/a/3111795/1063287

But I don't quite understand how it operates or exactly how it could be applied to the above scenario:

If you don't know the key, you can iterate over the files:

for filename, file in request.FILES.iteritems():
    name = request.FILES[filename].name

Solution

  • This seems a bit dodgy cause I'm not quite sure how it works yet, but it is working.

    It's a Mongo implementation, however I am adding it here because I think the takeaway is that you can define and access multiple file inputs where the name is a dynamic entity as are the number of inputs.

    What enabled this was using iteritems().

    Python

    for key, value in request.files.iteritems():
        uploaded_image = request.files[key]
        name, ext = os.path.splitext(uploaded_image.filename)
        if ext not in ('.png','.jpg','.jpeg','.JPG','.gif'):
            return "File extension not allowed."
        if uploaded_image and uploaded_image.file:
            raw = uploaded_image.file.read()
            filename = uploaded_image.filename
            dbname = 'grid_files'
            db = connection[dbname]
            fs = gridfs.GridFS(db)
            fs.put(raw,filename=filename, user_email = user_email)
    

    This adds each image to the database with a filename and a user email for unique identification (as well as time and length fields automatically generated by MongoDB).

    On the client side, the inputs were appended to the FormData object with:

    jQuery

    var image_inputs = $("#my_form input[type=file]");
    $.each(image_inputs,function(obj,v) { 
    var file = v.files[0];
    var filename = $(v).attr("data-img_filename");
    var name = $(v).attr("id");
    myFormData.append(name, file, filename);
    });
    

    And it seems the filename is automatically included without needing to define it as above:

    https://stackoverflow.com/a/21942376/1063287