I've been trying to upload a file using the box v2 api with requests.
So far I had little luck though. Maybe someone here can help me see what I'm actually doing wrong.
file_name = "%s%s" % (slugify(sync_file.description), file_suffix)
file_handle = open(settings.MEDIA_ROOT + str(sync_file.document), 'rb')
folder_id = str(sync_file.patient.box_patient_folder_id)
r = requests.post(
files_url,
headers=headers,
files={
file_name: file_handle,
"folder_id": folder_id,
},
)
My authentication works, because I'm creating a folder just before that, using the same data.
A response looks something like this:
{
u'status': 404,
u'code': u'not_found',
u'help_url': u'http://developers.box.com/docs/#errors',
u'request_id': u'77019510950608f791a0c1',
u'message': u'Not Found',
u'type': u'error'
}
Maybe someone on here ran into a similar issue.
Method 1: Using the Python's os Module: Also, the enctype attribute with "multi-part/form-data" value will help the HTML form to upload a file. Lastly, we need the input tag with the filename attribute to upload the file we want. Lastly, we need the input tag with the filename attribute to upload the file we want.
Run the Application by running “python multiplefilesupload.py”. Go to browser and type “http://localhost:5000”, you will see “upload files” in browser.
Send the data using curl's –d or –data option. To execute a CURL file upload, you need to use the –d command-line option and begin data with the @ symbol. The file's name should come after the data with @ symbol so CURL can read it and send it to the server.
You need to pass 2 Python dictionaries, files and data. files are {uniqFileName:openFileObj}
, and data are {uniqFileName:filename}
. Below is the upload method from my box class. And remember to add a final entry in data, 'folder_id': destination_id
.
def uploadFiles(self, ufiles, folid):
'''uploads 1 or more files in the ufiles list of tuples containing
(src fullpath, dest name). folid is the id of the folder to
upload to.'''
furl = URL2 + 'files/data'
data, files = {}, {}
for i, v in enumerate(ufiles):
ff = v[0]
fn = v[1]
#copy to new, renamed file in tmp folder if necessary
#can't find a way to do this with the api
if os.path.basename(ff) != fn:
dest = os.path.join(TMP, fn)
shutil.copy2(ff, dest)
ff = dest
f = open(ff, 'rb')
k = 'filename' + str(i)
data[k] = fn
files[k] = f
data['folder_id'] = folid
res = self.session.post(furl, files=files, data=data)
for k in files:
files[k].close()
return res.status_code
Here is a sample call:
destFol = '406600304'
ret = box.uploadFile((('c:/1temp/hc.zip', 'hz.zip'),), destFol)
Like I said, the above function is a method of a class, with an instance attr that holds a requests session. But you can use requests.post
instead of self.session.post
, and it will work just the same. Just remember to add the headers with your apikey and token if you do it outside a session.
According to the documentation, you are supposed to be able to rename the file by giving it a new name in the data dict. But I can't make this work except by copying the src file to a temp dir with the desired name and uploading that. It's a bit of a hack, but it works.
good luck, Mike
As someone requested my implementation, I figured I would put it out here for anyone trying to achieve something similar.
files_url = "%s/files/content" % (settings.BOX_API_HOST)
headers = {"Authorization": "BoxAuth api_key=%s&auth_token=%s" %
(settings.BOX_API_KEY, self.doctor.box_auth_token)
}
file_root, file_suffix = os.path.splitext(str(self.document))
filename = "%s%s" % (slugify(self.description), file_suffix)
files = {
'filename1': open(settings.MEDIA_ROOT + str(self.document), 'rb'),
}
data = {
'filename1': filename,
'folder_id': str(self.patient.get_box_folder()),
}
r = requests.post(files_url,
headers=headers,
files=files,
data=data)
file_response = simplejson.loads(r.text)
try:
if int(file_response['entries'][0]['id']) > 0:
box_file_id = int(file_response['entries'][0]['id'])
#Update the name of file
file_update_url = "%s/files/%s" % (settings.BOX_API_HOST, box_file_id)
data_update = {"name": filename}
file_update = requests.put(file_update_url,
data=simplejson.dumps(data_update),
headers=headers)
LocalDocument.objects.filter(id=self.id).update(box_file_id=box_file_id)
except:
pass
So in essence, I needed to send the file and retrieve the ID of the newly updated file and send another request to box. Personally, I don't like it either, but it works for me and haven't been able to find any other implementations that do the correct naming from the get-go.
Hope someone can benefit from this snippet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With