how to upload a file using request.Post in python [duplicate] - python
I'm performing a simple task of uploading a file using Python requests library. I searched Stack Overflow and no one seemed to have the same problem, namely, that the file is not received by the server:
import requests
url='http://nesssi.cacr.caltech.edu/cgi-bin/getmulticonedb_release2.cgi/post'
files={'files': open('file.txt','rb')}
values={'upload_file' : 'file.txt' , 'DB':'photcat' , 'OUT':'csv' , 'SHORT':'short'}
r=requests.post(url,files=files,data=values)
I'm filling the value of 'upload_file' keyword with my filename, because if I leave it blank, it says
Error - You must select a file to upload!
And now I get
File file.txt of size bytes is uploaded successfully!
Query service results: There were 0 lines.
Which comes up only if the file is empty. So I'm stuck as to how to send my file successfully. I know that the file works because if I go to this website and manually fill in the form it returns a nice list of matched objects, which is what I'm after. I'd really appreciate all hints.
Some other threads related (but not answering my problem):
Send file using POST from a Python script
http://docs.python-requests.org/en/latest/user/quickstart/#response-content
Uploading files using requests and send extra data
http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow
If upload_file is meant to be the file, use:
files = {'upload_file': open('file.txt','rb')}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}
r = requests.post(url, files=files, data=values)
and requests will send a multi-part form POST body with the upload_file field set to the contents of the file.txt file.
The filename will be included in the mime header for the specific field:
>>> import requests
>>> open('file.txt', 'wb') # create an empty demo file
<_io.BufferedWriter name='file.txt'>
>>> files = {'upload_file': open('file.txt', 'rb')}
>>> print(requests.Request('POST', 'http://example.com', files=files).prepare().body.decode('ascii'))
--c226ce13d09842658ffbd31e0563c6bd
Content-Disposition: form-data; name="upload_file"; filename="file.txt"
--c226ce13d09842658ffbd31e0563c6bd--
Note the filename="file.txt" parameter.
You can use a tuple for the files mapping value, with between 2 and 4 elements, if you need more control. The first element is the filename, followed by the contents, and an optional content-type header value and an optional mapping of additional headers:
files = {'upload_file': ('foobar.txt', open('file.txt','rb'), 'text/x-spam')}
This sets an alternative filename and content type, leaving out the optional headers.
If you are meaning the whole POST body to be taken from a file (with no other fields specified), then don't use the files parameter, just post the file directly as data. You then may want to set a Content-Type header too, as none will be set otherwise. See Python requests - POST data from a file.
(2018) the new python requests library has simplified this process, we can use the 'files' variable to signal that we want to upload a multipart-encoded file
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)
r.text
Client Upload
If you want to upload a single file with Python requests library, then requests lib supports streaming uploads, which allow you to send large files or streams without reading into memory.
with open('massive-body', 'rb') as f:
requests.post('http://some.url/streamed', data=f)
Server Side
Then store the file on the server.py side such that save the stream into file without loading into the memory. Following is an example with using Flask file uploads.
#app.route("/upload", methods=['POST'])
def upload_file():
from werkzeug.datastructures import FileStorage
FileStorage(request.stream).save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return 'OK', 200
Or use werkzeug Form Data Parsing as mentioned in a fix for the issue of "large file uploads eating up memory" in order to avoid using memory inefficiently on large files upload (s.t. 22 GiB file in ~60 seconds. Memory usage is constant at about 13 MiB.).
#app.route("/upload", methods=['POST'])
def upload_file():
def custom_stream_factory(total_content_length, filename, content_type, content_length=None):
import tempfile
tmpfile = tempfile.NamedTemporaryFile('wb+', prefix='flaskapp', suffix='.nc')
app.logger.info("start receiving file ... filename => " + str(tmpfile.name))
return tmpfile
import werkzeug, flask
stream, form, files = werkzeug.formparser.parse_form_data(flask.request.environ, stream_factory=custom_stream_factory)
for fil in files.values():
app.logger.info(" ".join(["saved form name", fil.name, "submitted as", fil.filename, "to temporary file", fil.stream.name]))
# Do whatever with stored file at `fil.stream.name`
return 'OK', 200
You can send any file via post api while calling the API just need to mention files={'any_key': fobj}
import requests
import json
url = "https://request-url.com"
headers = {"Content-Type": "application/json; charset=utf-8"}
with open(filepath, 'rb') as fobj:
response = requests.post(url, headers=headers, files={'file': fobj})
print("Status Code", response.status_code)
print("JSON Response ", response.json())
#martijn-pieters answer is correct, however I wanted to add a bit of context to data= and also to the other side, in the Flask server, in the case where you are trying to upload files and a JSON.
From the request side, this works as Martijn describes:
files = {'upload_file': open('file.txt','rb')}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}
r = requests.post(url, files=files, data=values)
However, on the Flask side (the receiving webserver on the other side of this POST), I had to use form
#app.route("/sftp-upload", methods=["POST"])
def upload_file():
if request.method == "POST":
# the mimetype here isnt application/json
# see here: https://stackoverflow.com/questions/20001229/how-to-get-posted-json-in-flask
body = request.form
print(body) # <- immutable dict
body = request.get_json() will return nothing. body = request.get_data() will return a blob containing lots of things like the filename etc.
Here's the bad part: on the client side, changing data={} to json={} results in this server not being able to read the KV pairs! As in, this will result in a {} body above:
r = requests.post(url, files=files, json=values). # No!
This is bad because the server does not have control over how the user formats the request; and json= is going to be the habbit of requests users.
Upload:
with open('file.txt', 'rb') as f:
files = {'upload_file': f.read()}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}
r = requests.post(url, files=files, data=values)
Download (Django):
with open('file.txt', 'wb') as f:
f.write(request.FILES['upload_file'].file.read())
Regarding the answers given so far, there was always something missing that prevented it to work on my side. So let me show you what worked for me:
import json
import os
import requests
API_ENDPOINT = "http://localhost:80"
access_token = "sdfJHKsdfjJKHKJsdfJKHJKysdfJKHsdfJKHs" # TODO: get fresh Token here
def upload_engagement_file(filepath):
url = API_ENDPOINT + "/api/files" # add any URL parameters if needed
hdr = {"Authorization": "Bearer %s" % access_token}
with open(filepath, "rb") as fobj:
file_obj = fobj.read()
file_basename = os.path.basename(filepath)
file_to_upload = {"file": (str(file_basename), file_obj)}
finfo = {"fullPath": filepath}
upload_response = requests.post(url, headers=hdr, files=file_to_upload, data=finfo)
fobj.close()
# print("Status Code ", upload_response.status_code)
# print("JSON Response ", upload_response.json())
return upload_response
Note that requests.post(...) needs
a url parameter, containing the full URL of the API endpoint you're calling, using the API_ENDPOINT, assuming we have an http://localhost:8000/api/files endpoint to POST a file
a headers parameter, containing at least the authorization (bearer token)
a files parameter taking the name of the file plus the entire file content
a data parameter taking just the path and file name
Installation required (console):
pip install requests
What you get back from the function call is a response object containing a status code and also the full error message in JSON format. The commented print statements at the end of upload_engagement_file are showing you how you can access them.
Note: Some useful additional information about the requests library can be found here
Some may need to upload via a put request and this is slightly different that posting data. It is important to understand how the server expects the data in order to form a valid request. A frequent source of confusion is sending multipart-form data when it isn't accepted. This example uses basic auth and updates an image via a put request.
url = 'foobar.com/api/image-1'
basic = requests.auth.HTTPBasicAuth('someuser', 'password123')
# Setting the appropriate header is important and will vary based
# on what you upload
headers = {'Content-Type': 'image/png'}
with open('image-1.png', 'rb') as img_1:
r = requests.put(url, auth=basic, data=img_1, headers=headers)
While the requests library makes working with http requests a lot easier, some of its magic and convenience obscures just how to craft more nuanced requests.
In Ubuntu you can apply this way,
to save file at some location (temporary) and then open and send it to API
path = default_storage.save('static/tmp/' + f1.name, ContentFile(f1.read()))
path12 = os.path.join(os.getcwd(), "static/tmp/" + f1.name)
data={} #can be anything u want to pass along with File
file1 = open(path12, 'rb')
header = {"Content-Disposition": "attachment; filename=" + f1.name, "Authorization": "JWT " + token}
res= requests.post(url,data,header)
Related
I want to send image from my computer to server [duplicate]
I'm performing a simple task of uploading a file using Python requests library. I searched Stack Overflow and no one seemed to have the same problem, namely, that the file is not received by the server: import requests url='http://nesssi.cacr.caltech.edu/cgi-bin/getmulticonedb_release2.cgi/post' files={'files': open('file.txt','rb')} values={'upload_file' : 'file.txt' , 'DB':'photcat' , 'OUT':'csv' , 'SHORT':'short'} r=requests.post(url,files=files,data=values) I'm filling the value of 'upload_file' keyword with my filename, because if I leave it blank, it says Error - You must select a file to upload! And now I get File file.txt of size bytes is uploaded successfully! Query service results: There were 0 lines. Which comes up only if the file is empty. So I'm stuck as to how to send my file successfully. I know that the file works because if I go to this website and manually fill in the form it returns a nice list of matched objects, which is what I'm after. I'd really appreciate all hints. Some other threads related (but not answering my problem): Send file using POST from a Python script http://docs.python-requests.org/en/latest/user/quickstart/#response-content Uploading files using requests and send extra data http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow
If upload_file is meant to be the file, use: files = {'upload_file': open('file.txt','rb')} values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'} r = requests.post(url, files=files, data=values) and requests will send a multi-part form POST body with the upload_file field set to the contents of the file.txt file. The filename will be included in the mime header for the specific field: >>> import requests >>> open('file.txt', 'wb') # create an empty demo file <_io.BufferedWriter name='file.txt'> >>> files = {'upload_file': open('file.txt', 'rb')} >>> print(requests.Request('POST', 'http://example.com', files=files).prepare().body.decode('ascii')) --c226ce13d09842658ffbd31e0563c6bd Content-Disposition: form-data; name="upload_file"; filename="file.txt" --c226ce13d09842658ffbd31e0563c6bd-- Note the filename="file.txt" parameter. You can use a tuple for the files mapping value, with between 2 and 4 elements, if you need more control. The first element is the filename, followed by the contents, and an optional content-type header value and an optional mapping of additional headers: files = {'upload_file': ('foobar.txt', open('file.txt','rb'), 'text/x-spam')} This sets an alternative filename and content type, leaving out the optional headers. If you are meaning the whole POST body to be taken from a file (with no other fields specified), then don't use the files parameter, just post the file directly as data. You then may want to set a Content-Type header too, as none will be set otherwise. See Python requests - POST data from a file.
(2018) the new python requests library has simplified this process, we can use the 'files' variable to signal that we want to upload a multipart-encoded file url = 'http://httpbin.org/post' files = {'file': open('report.xls', 'rb')} r = requests.post(url, files=files) r.text
Client Upload If you want to upload a single file with Python requests library, then requests lib supports streaming uploads, which allow you to send large files or streams without reading into memory. with open('massive-body', 'rb') as f: requests.post('http://some.url/streamed', data=f) Server Side Then store the file on the server.py side such that save the stream into file without loading into the memory. Following is an example with using Flask file uploads. #app.route("/upload", methods=['POST']) def upload_file(): from werkzeug.datastructures import FileStorage FileStorage(request.stream).save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) return 'OK', 200 Or use werkzeug Form Data Parsing as mentioned in a fix for the issue of "large file uploads eating up memory" in order to avoid using memory inefficiently on large files upload (s.t. 22 GiB file in ~60 seconds. Memory usage is constant at about 13 MiB.). #app.route("/upload", methods=['POST']) def upload_file(): def custom_stream_factory(total_content_length, filename, content_type, content_length=None): import tempfile tmpfile = tempfile.NamedTemporaryFile('wb+', prefix='flaskapp', suffix='.nc') app.logger.info("start receiving file ... filename => " + str(tmpfile.name)) return tmpfile import werkzeug, flask stream, form, files = werkzeug.formparser.parse_form_data(flask.request.environ, stream_factory=custom_stream_factory) for fil in files.values(): app.logger.info(" ".join(["saved form name", fil.name, "submitted as", fil.filename, "to temporary file", fil.stream.name])) # Do whatever with stored file at `fil.stream.name` return 'OK', 200
You can send any file via post api while calling the API just need to mention files={'any_key': fobj} import requests import json url = "https://request-url.com" headers = {"Content-Type": "application/json; charset=utf-8"} with open(filepath, 'rb') as fobj: response = requests.post(url, headers=headers, files={'file': fobj}) print("Status Code", response.status_code) print("JSON Response ", response.json())
#martijn-pieters answer is correct, however I wanted to add a bit of context to data= and also to the other side, in the Flask server, in the case where you are trying to upload files and a JSON. From the request side, this works as Martijn describes: files = {'upload_file': open('file.txt','rb')} values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'} r = requests.post(url, files=files, data=values) However, on the Flask side (the receiving webserver on the other side of this POST), I had to use form #app.route("/sftp-upload", methods=["POST"]) def upload_file(): if request.method == "POST": # the mimetype here isnt application/json # see here: https://stackoverflow.com/questions/20001229/how-to-get-posted-json-in-flask body = request.form print(body) # <- immutable dict body = request.get_json() will return nothing. body = request.get_data() will return a blob containing lots of things like the filename etc. Here's the bad part: on the client side, changing data={} to json={} results in this server not being able to read the KV pairs! As in, this will result in a {} body above: r = requests.post(url, files=files, json=values). # No! This is bad because the server does not have control over how the user formats the request; and json= is going to be the habbit of requests users.
Upload: with open('file.txt', 'rb') as f: files = {'upload_file': f.read()} values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'} r = requests.post(url, files=files, data=values) Download (Django): with open('file.txt', 'wb') as f: f.write(request.FILES['upload_file'].file.read())
Regarding the answers given so far, there was always something missing that prevented it to work on my side. So let me show you what worked for me: import json import os import requests API_ENDPOINT = "http://localhost:80" access_token = "sdfJHKsdfjJKHKJsdfJKHJKysdfJKHsdfJKHs" # TODO: get fresh Token here def upload_engagement_file(filepath): url = API_ENDPOINT + "/api/files" # add any URL parameters if needed hdr = {"Authorization": "Bearer %s" % access_token} with open(filepath, "rb") as fobj: file_obj = fobj.read() file_basename = os.path.basename(filepath) file_to_upload = {"file": (str(file_basename), file_obj)} finfo = {"fullPath": filepath} upload_response = requests.post(url, headers=hdr, files=file_to_upload, data=finfo) fobj.close() # print("Status Code ", upload_response.status_code) # print("JSON Response ", upload_response.json()) return upload_response Note that requests.post(...) needs a url parameter, containing the full URL of the API endpoint you're calling, using the API_ENDPOINT, assuming we have an http://localhost:8000/api/files endpoint to POST a file a headers parameter, containing at least the authorization (bearer token) a files parameter taking the name of the file plus the entire file content a data parameter taking just the path and file name Installation required (console): pip install requests What you get back from the function call is a response object containing a status code and also the full error message in JSON format. The commented print statements at the end of upload_engagement_file are showing you how you can access them. Note: Some useful additional information about the requests library can be found here
Some may need to upload via a put request and this is slightly different that posting data. It is important to understand how the server expects the data in order to form a valid request. A frequent source of confusion is sending multipart-form data when it isn't accepted. This example uses basic auth and updates an image via a put request. url = 'foobar.com/api/image-1' basic = requests.auth.HTTPBasicAuth('someuser', 'password123') # Setting the appropriate header is important and will vary based # on what you upload headers = {'Content-Type': 'image/png'} with open('image-1.png', 'rb') as img_1: r = requests.put(url, auth=basic, data=img_1, headers=headers) While the requests library makes working with http requests a lot easier, some of its magic and convenience obscures just how to craft more nuanced requests.
In Ubuntu you can apply this way, to save file at some location (temporary) and then open and send it to API path = default_storage.save('static/tmp/' + f1.name, ContentFile(f1.read())) path12 = os.path.join(os.getcwd(), "static/tmp/" + f1.name) data={} #can be anything u want to pass along with File file1 = open(path12, 'rb') header = {"Content-Disposition": "attachment; filename=" + f1.name, "Authorization": "JWT " + token} res= requests.post(url,data,header)
Python rest client for formData type
I am writing a rest client in pytho with request api The rest server has rest api to upload file , it takes two parameters - file - the actual file and its type is formData fileName - the name of file in string and its type is also formData I am using the below code file = f = open('C:/tmp/test.txt', 'rb') headers={'content-type':'multipart/form-data'} r = requests.post(url+'/rest/2.0/process?'+file=f&fileName='test.txt' but somehow its not working can anybody help where it needs correction the corresponding rest server method is #POST #Consumes({"multipart/form-data"}) #TypeHint(Test.class) public Response deployTestDefinition(#FormDataParam("file") InputStream file, #FormDataParam("fileName") String fileName) { my current request is like below : f = open('C:/tmp/Test.txt', 'rb') files = {'file' : ('Test.txt', f), 'fileName':'Test.txt'} headers={'content-type':'multipart/form-data'} r = requests.post(url+'/rest/2.0/process',files=files,headers=headers,cookies=token,verify=False) but still not working status 400 Thanks
It appears that you're not uploading the file properly. As per requests documentation: url = 'https://httpbin.org/post' files = {'file': open('report.xls', 'rb')} r = requests.post(url, files=files) You need to specify the files parameter and put the f instance in that dictionary.
How to upload a binary/video file using Python http.client PUT method?
I am communicating with an API using HTTP.client in Python 3.6.2. In order to upload a file it requires a three stage process. I have managed to talk successfully using POST methods and the server returns data as I expect. However, the stage that requires the actual file to be uploaded is a PUT method - and I cannot figure out how to syntax the code to include a pointer to the actual file on my storage - the file is an mp4 video file. Here is a snippet of the code with my noob annotations :) #define connection as HTTPS and define URL uploadstep2 = http.client.HTTPSConnection("grabyo-prod.s3-accelerate.amazonaws.com") #define headers headers = { 'accept': "application/json", 'content-type': "application/x-www-form-urlencoded" } #define the structure of the request and send it. #Here it is a PUT request to the unique URL as defined above with the correct file and headers. uploadstep2.request("PUT", myUniqueUploadUrl, body="C:\Test.mp4", headers=headers) #get the response from the server uploadstep2response = uploadstep2.getresponse() #read the data from the response and put to a usable variable step2responsedata = uploadstep2response.read() The response I am getting back at this stage is an "Error 400 Bad Request - Could not obtain the file information." I am certain this relates to the body="C:\Test.mp4" section of the code. Can you please advise how I can correctly reference a file within the PUT method? Thanks in advance
uploadstep2.request("PUT", myUniqueUploadUrl, body="C:\Test.mp4", headers=headers) will put the actual string "C:\Test.mp4" in the body of your request, not the content of the file named "C:\Test.mp4" as you expect. You need to open the file, read it's content then pass it as body. Or to stream it, but AFAIK http.client does not support that, and since your file seems to be a video, it is potentially huge and will use plenty of RAM for no good reason. My suggestion would be to use requests, which is a way better lib to do this kind of things: import requests with open(r'C:\Test.mp4'), 'rb') as finput: response = requests.put('https://grabyo-prod.s3-accelerate.amazonaws.com/youruploadpath', data=finput) print(response.json())
I do not know if it is useful for you, but you can try to send a POST request with requests module : import requests url = "" data = {'title':'metadata','timeDuration':120} mp3_f = open('/path/your_file.mp3', 'rb') files = {'messageFile': mp3_f} req = requests.post(url, files=files, json=data) print (req.status_code) print (req.content) Hope it helps .
Simulate multipart/form-data file upload with Falcon's Testing module
This simple Falcon API will take a HTTP POST with enctype=multipart/form-data and a file upload in the file parameter and print the file's content on the console: # simple_api.py import cgi import falcon class SomeTestApi(object): def on_post(self, req, resp): upload = cgi.FieldStorage(fp=req.stream, environ=req.env) upload = upload['file'].file.read() print(upload) app = falcon.API() app.add_route('/', SomeTestApi()) One might also use the falcon-multipart middleware to achieve the same goal. To try it out, run it e.g. with gunicorn (pip install gunicorn), gunicorn simple_api.py then use cUrl (or any REST client of choice) to upload a text file: # sample.txt this is some sample text curl -F "file=#sample.txt" localhost:8000 I would like to test this API now with Falcon's testing helpers by simulating a file upload. However, I do not understand yet how to do this (if it is possible at all?). The simulate_request method has a file_wrapper parameter which might be useful but from the documentation I do not understand how this is supposed to be filled. Any suggestions?
This is what I came up with, which tries to simulate what my Chrome does. Note that this simulates the case when you are uploading only one file, but you can simply modify this function to upload multiple files, each one separated by two new lines. def create_multipart(data, fieldname, filename, content_type): """ Basic emulation of a browser's multipart file upload """ boundry = '----WebKitFormBoundary' + random_string(16) buff = io.BytesIO() buff.write(b'--') buff.write(boundry.encode()) buff.write(b'\r\n') buff.write(('Content-Disposition: form-data; name="%s"; filename="%s"' % \ (fieldname, filename)).encode()) buff.write(b'\r\n') buff.write(('Content-Type: %s' % content_type).encode()) buff.write(b'\r\n') buff.write(b'\r\n') buff.write(data) buff.write(b'\r\n') buff.write(boundry.encode()) buff.write(b'--\r\n') headers = {'Content-Type': 'multipart/form-data; boundary=%s' %boundry} headers['Content-Length'] = str(buff.tell()) return buff.getvalue(), headers You can then use this function like the following: with open('test/resources/foo.pdf', 'rb') as f: foodata = f.read() # Create the multipart data data, headers = create_multipart(foodata, fieldname='uploadFile', filename='foo.pdf', content_type='application/pdf') # Post to endpoint client.simulate_request(method='POST', path=url, headers=headers, body=data)
You can craft a suitable request body and Content-Type using the encode_multipart_formdata function in urllib3, documented here. An example usage: from falcon import testing import pytest import myapp import urllib3 # Depending on your testing strategy and how your application # manages state, you may be able to broaden the fixture scope # beyond the default 'function' scope used in this example. #pytest.fixture() def client(): # Assume the hypothetical `myapp` package has a function called # `create()` to initialize and return a `falcon.App` instance. return testing.TestClient(myapp.create()) # a dictionary mapping the HTML form label to the file uploads fields = { 'file_1_form_label': ( # label in HTML form object 'file1.txt', # filename open('path/to/file1.txt').read(), # file contents 'text/plain' # MIME type ), 'file_2_form_label': ( 'file2.json', open('path/to/file2.json').read(), 'application/json' ) } # create the body and header body, content_type_header = urllib3.encode_multipart_formdata(fields) # NOTE: modify these headers to reflect those generated by your browser # and/or required by the falcon application you're testing headers = { 'Content-Type': content_type_header, } # craft the mock query using the falcon testing framework response = client.simulate_request( method="POST", path='/app_path', headers=headers, body=body) print(response.status_code) Note the syntax of the fields object, which is used as input for the encode_multipart_formdata function. See Tim Head's blog post for another example: https://betatim.github.io/posts/python-create-multipart-formdata/ Falcon testing example copied from their docs: https://falcon.readthedocs.io/en/stable/api/testing.html
Uploading a file to a Django PUT handler using the requests library
I have a REST PUT request to upload a file using the Django REST framework. Whenever I am uploading a file using the Postman REST client it works fine: But when I try to do this with my code: import requests API_URL = "http://123.316.118.92:8888/api/" API_TOKEN = "1682b28041de357d81ea81db6a228c823ad52967" URL = API_URL + 'configuration/configlet/31' #files = { files = {'file': open('configlet.txt','rb')} print URL print "Update Url ==-------------------" headers = {'Content-Type' : 'text/plain','Authorization':API_TOKEN} resp = requests.put(URL,files=files,headers = headers) print resp.text print resp.status_code I am getting an error on the server side: MultiValueDictKeyError at /api/configuration/31/ "'file'" I am passing file as key but still getting above error please do let me know what might I am doing wrong here. This is how my Django server view looks def put(self, request,id,format=None): configlet = self.get_object(id) configlet.config_path.delete(save=False) file_obj = request.FILES['file'] configlet.config_path = file_obj file_content = file_obj.read() params = parse_file(file_content) configlet.parameters = json.dumps(params) logger.debug("File content: "+str(file_content)) configlet.save()
For this to work you need to send a multipart/form-data body. You should not be setting the content-type of the whole request to text/plain here; set only the mime-type of the one part: files = {'file': ('configlet.txt', open('configlet.txt','rb'), 'text/plain')} headers = {'Authorization': API_TOKEN} resp = requests.put(URL, files=files, headers=headers) This leaves setting the Content-Type header for the request as a whole to the library, and using files sets that to multipart/form-data for you.