views:

73

answers:

1

So I've created a form that includes the following item

<input type="file" name="form_file" multiple/>

This tells the browser to allow the user to select multiple files while browsing. The problem I am having is is that when reading / writing the files that are being uploaded, I can only see the last of the files, not all of them. I was pretty sure I've seen this done before, but had no luck searching. Here's generally what my read looks like

if request.FILES:
    filename = parent_id + str(random.randrange(0,100))
    output_file = open(settings.PROJECT_PATH + "static/img/inventory/" + filename + ".jpg", "w")
    output_file.write(request.FILES["form_file"].read())
    output_file.close()

Now, as you can see I'm not looping through each file, because I've tried a few different ways and can't seem to find the other files (in objects and such)

I added in this print(request.FILES["form_file"]) and was only getting the last filename, as expected. Is there some trick to get to the other files? Am I stuck with a single file upload? Thanks!

+1  A: 

Based on your file element form_file, the value in request.FILES['form_file'] should be a list of files. So you can do something like:

for upfile in request.FILES.getlist('form_file'):
    filename = upfile.name
    # instead of "filename" specify the full path and filename of your choice here
    fd = open(filename, 'w')
    fd.write(upfile['content'])
    fd.close()

Using chunks:

for upfile in request.FILES.getlist('form_file'):
    filename = upfile.name
    fd = open(filename, 'w+')  # or 'wb+' for binary file
    for chunk in upfile.chunks():
        fd.write(chunk)
    fd.close()
ars
I tried that, but only got bits of the file, or "chunks" I think they call them in django. It was pretty weird, I had to switch to this method to actually get the entire file. The chunks were 4kb.
Shane Reustle
Maybe you can try the recipe for handling chunks mentioned in the docs : http://docs.djangoproject.com/en/dev/topics/http/file-uploads/#handling-uploaded-files
ars
When dealing with chunks, how do I know when I'm finished my first file, and starting my second?
Shane Reustle
@Shane: updated the answer.
ars
I've tried that, but upfile is a string no matter what (when I upload a single file, or multiple files) which is why I can't do chunks() on it.
Shane Reustle
When I print request.FILES when uploading 1 file: `<MultiValueDict: {u'form_file': [<InMemoryUploadedFile: n556057924_592062_5411.jpg (image/jpeg)>]}>` and when uploading 2 files `<MultiValueDict: {u'form_file': [<InMemoryUploadedFile: n556057924_839946_4670.jpg (image/jpeg)>, <InMemoryUploadedFile: n556057924_839947_4940.jpg (image/jpeg)>]}>`
Shane Reustle
This is really strange - that you're seeing upfile as a string. The printout you pasted shows that FILES is a dictionary, form_file is a key to a list, and the elements of that list are UploadedFile instances. So I'm at a loss to explain why you see a string ...
ars
What does it show if, instead of `print request.FILES`, you do: `print request.FILES['form_file'][0]`? If that doesn't show up as a string, the neither should `upfile`. (BTW, made a small edit to use the name property for filename, but I don't think this explains your problem.)
ars
I tried to access [0] and [1], but every time I did that I got `'InMemoryUploadedFile' object does not support indexing`. I guess because it's a string? So weird!
Shane Reustle
Also, I am doing these tests with both small and large files (totaling under the 2.5mb limit where it starts chunking, and totaling over to force chunking)
Shane Reustle
The difference is I get `'TemporaryUploadedFile' object does not support indexing` when it is over 2.5mb. I assume the different wording is because it is chunked.
Shane Reustle
@Shane: try the change I made above to use `request.FILES.getlist` directly. This should ensure that you're getting a list back (instead of a string or other strange behavior).
ars
request.FILES.getlist returns `<bound method MultiValueDict.getlist of <MultiValueDict: {u'form_file': [<InMemoryUploadedFile: 100_1717.JPG (image/jpeg)>, <InMemoryUploadedFile: 100_1718.JPG (image/jpeg)>]}>>` but when I try to loop through it I get `'instancemethod' object is not iterable` on both >2.5mb and <2.5mb uploads
Shane Reustle
@Shane: you have to specify the argument: `request.FILES.getlist('form_file')`
ars
Jackpot. Thank you very much for the persistent help!
Shane Reustle
@Shane: you're welcome; glad it worked out! :)
ars