The Python requests module provides good documentation on how to upload a single file in a single request:
files = {'file': open('report.xls', 'rb')}
I tried extending that example by using this code in an attempt to upload multiple files:
files = {'file': [open('report.xls', 'rb'), open('report2.xls, 'rb')]}
but it resulted in this error:
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 1052, in splittype
match = _typeprog.match(url)
TypeError: expected string or buffer
Is it possible to upload a list of files in a single request using this module, and how?
To upload a list of files with the same key value in a single request, you can create a list of tuples with the first item in each tuple as the key value and the file object as the second:
files = [('file', open('report.xls', 'rb')), ('file', open('report2.xls', 'rb'))]
Multiple files with different key values can be uploaded by adding multiple dictionary entries:
files = {'file1': open('report.xls', 'rb'), 'file2': open('otherthing.txt', 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
The documentation contains a clear answer.
Quoted:
You can send multiple files in one request. For example, suppose you
want to upload image files to an HTML form with a multiple file field
‘images’:
To
do that, just set files to a list of tuples of (form_field_name,
file_info):
url = 'http://httpbin.org/post'
multiple_files = [('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
r = requests.post(url, files=multiple_files)
r.text
# {
# ...
# 'files': {'images': 'data:image/png;base64,iVBORw ....'}
# 'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
# ...
# }
In case you have the files from a form and want to forward it to other URL or to API. Here is an example with multiple files and other form data to forward to other URL.
images = request.files.getlist('images')
files = []
for image in images:
files.append(("images", (image.filename, image.read(), image.content_type)))
r = requests.post(url="http://example.com/post", data={"formdata1": "strvalue", "formdata2": "strvalue2"}, files=files)
You need to create a file list to upload multiple images:
file_list = [
('Key_here', ('file_name1.jpg', open('file_path1.jpg', 'rb'), 'image/png')),
('key_here', ('file_name2.jpg', open('file_path2.jpg', 'rb'), 'image/png'))
]
r = requests.post(url, files=file_list)
If you want to send files on the same key you need to keep the key same for each element, and for a different key just change the keys.
Source : https://stackabuse.com/the-python-requests-module/
I'm a little bit confused, but directly opening file in request (however same is written in official requests guide) is not so "safe".
Just try:
import os
import requests
file_path = "/home/user_folder/somefile.txt"
files = {'somefile': open(file_path, 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
Yes, all will be ok, but:
os.rename(file_path, file_path)
And you will get:
PermissionError:The process cannot access the file because it is being used by another process
Please, correct me if I'm not right, but it seems that file is still opened and I do not know any way to close it.
Instead of this I use:
import os
import requests
#let it be folder with files to upload
folder = "/home/user_folder/"
#dict for files
upload_list = []
for files in os.listdir(folder):
with open("{folder}{name}".format(folder=folder, name=files), "rb") as data:
upload_list.append(files, data.read())
r = request.post("https://httpbin.org/post", files=upload_list)
#trying to rename uploaded files now
for files in os.listdir(folder):
os.rename("{folder}{name}".format(folder=folder, name=files), "{folder}{name}".format(folder=folder, name=files))
Now we do not get errors, so I recommend to use this way to upload multiple files or you could receive some errors.
Hope this answer well help somebody and save priceless time.
Using These methods File will Automatically be closed.
Method 1
with open("file_1.txt", "rb") as f1, open("file_2.txt", "rb") as f2:
files = [f1, f2]
response = requests.post('URL', files=files)
But When You're Opening Multiple Files This Can Get Pretty long
Method 2:
files = [open("forms.py", "rb"), open("data.db", "rb")]
response = requests.post('URL', files=files)
# Closing all Files
for file in files:
file.close()
If you have multiple files in a python list, you can use eval() in a comprehension to loop over the files in the requests post files parameter.
file_list = ['001.jpg', '002.jpg', '003.jpg']
files=[eval(f'("inline", open("{file}", "rb"))') for file in file_list ]
requests.post(
url=url,
files=files
)
In my case uploading all the images which are inside the folder just adding key with index
e.g. key = 'images' to e.g. 'images[0]' in the loop
photosDir = 'allImages'
def getFilesList(self):
listOfDir = os.listdir(os.path.join(os.getcwd()+photosDir))
setOfImg = []
for key,row in enumerate(listOfDir):
print(os.getcwd()+photosDir+str(row) , 'Image Path')
setOfImg.append((
'images['+str(key)+']',(row,open(os.path.join(os.getcwd()+photosDir+'/'+str(row)),'rb'),'image/jpg')
))
print(setOfImg)
return setOfImg
I'm using this code to download .torrent files:
torrent = urllib2.urlopen(torrent URL, timeout = 30)
output = open('mytorrent.torrent', 'wb')
output.write(torrent.read())
The resultant mytorrent.torrent file doesn't open in any bittorrent client and throws up "unable to parse meta file" error. The problem apparently is that although the torrent URL (e.g. http://torcache.com/torrent-file-1.torrent) ends with a '.torrent' suffix, it is compressed using gzip and needs to be uncompressed and then saved as a torrent file. I've confirmed this by unzipping the file in terminal:gunzip mytorrent.torrent > test.torrent and opening the file in the bittorrent client which opens fine.
How do I modify python to look up the file encoding and figure out how the file is compressed and use the right tool to uncompress it and save as a .torrent file?
gzip'ed data must be unziped. You can deteted this, if you look out for the content-encoding header.
import gzip, urllib2, StringIO
req = urllib2.Request(url)
opener = urllib2.build_opener()
response = opener.open(req)
data = response.read()
if response.info()['content-encoding'] == 'gzip':
gzipper = gzip.GzipFile(StringIO(fileobj=data))
plain = gzipper.read()
data = plain
output.write(data)
I'm trying to serve a txt file generated with some content and i am having some issues. I'vecreated the temp files and written the content using NamedTemporaryFile and just set delete to false to debug however the downloaded file does not contain anything.
My guess is the response values are not pointed to the correct file, hense nothing is being downloaded, heres my code:
f = NamedTemporaryFile()
f.write(p.body)
response = HttpResponse(FileWrapper(f), mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=test-%s.txt' % p.uuid
response['X-Sendfile'] = f.name
Have you considered just sending p.body through the response like this:
response = HttpResponse(mimetype='text/plain')
response['Content-Disposition'] = 'attachment; filename="%s.txt"' % p.uuid
response.write(p.body)
XSend requires the path to the file in
response['X-Sendfile']
So, you can do
response['X-Sendfile'] = smart_str(path_to_file)
Here, path_to_file is the full path to the file (not just the name of the file)
Checkout this django-snippet
There can be several problems with your approach:
file content does not have to be flushed, add f.flush() as mentioned in comment above
NamedTemporaryFile is deleted on closing, what might happen just as you exit your function, so the webserver has no chance to pick it up
temporary file name might be out of paths which web server is configured to send using X-Sendfile
Maybe it would be better to use StreamingHttpResponse instead of creating temporary files and X-Sendfile...
import urllib2;
url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0";
opener = urllib2.urlopen(url);
mimetype = "application/octet-stream"
response = HttpResponse(opener.read(), mimetype=mimetype)
response["Content-Disposition"]= "attachment; filename=aktel.png"
return response
I am trying to create a download of a file object. the file was added using django-filebrowser which means it is turn in to a string path to the the file. I have tried the following:
f = Obj.objects.get(id=obj_id)
myfile = FileObject(os.path.join(MEDIA_ROOT, f.Audio.path))
...
response = HttpResponse(myfile, content_type="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
The file that is downloaded contains the string of the path to the file location and not the file. Could anyone be of assistance on how to access the file object?
f = Obj.objects.get(id=obj_id)
myfile = open(os.path.join(MEDIA_ROOT, f.Audio.path)).read()
...
response = HttpResponse(myfile, content_type="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
NOTE! This is not memory friendly! Since the whole file is put into memory. You're better of using a webserver for file serving or if you want to use Django for file serving you could use xsendfile or have a look at this thread
You need to open the file and send it's binary contents back in the response. So something like:
fileObject = FileObject(os.path.join(MEDIA_ROOT, f.Audio.path))
myfile = open(fileObject.path)
response = HttpResponse(myfile.read(), mimetype="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
Hope that gets what you're looking for.
wrapper = FileWrapper(file("C:/pics.zip"))
content_type = mimetypes.guess_type(result.files)[0]
response = HttpResponse(wrapper, content_type=content_type)
response['Content-Length'] = os.path.getsize("C:/pics.zip")
response['Content-Disposition'] = "attachment; filename=pics.zip"
return response
pics.zip is a valid file with 3 pictures inside.
server response the download, but when I am going to open the zip, winrar says This archive is either in unknown format or damaged!
If I change the file path and the file name to a valid image C:/pic.jpg is downloaded damaged too.
What Im missing in this download view?
The problem is that you're not reading it as a binary file :)
This should work:
wrapper = FileWrapper(file("C:/pics.zip", 'rb'))