python - http multipart/form-data post request

  • Last Update :
  • Techknowledgy :

Basically, if you specify a files parameter (a dictionary), then requests will send a multipart/form-data POST instead of a application/x-www-form-urlencoded POST. You are not limited to using actual files in that dictionary, however:

import requests
   response ='', files = dict(foo = 'bar')) >>>

and lets you know what headers you posted with; in response.json() we have:

>>> from pprint
import pprint
   pprint(response.json()['headers']) {
      'Accept': '*/*',
      'Accept-Encoding': 'gzip, deflate',
      'Connection': 'close',
      'Content-Length': '141',
      'Content-Type': 'multipart/form-data; '
      'Host': '',
      'User-Agent': 'python-requests/2.21.0'

I'd use the tuple form with None as the filename, so that the filename="..." parameter is dropped from the request for those parts:

>>> files = {
      'foo': 'bar'
   } >>>
   print(requests.Request('POST', '', files = files).prepare().body.decode('utf8'))
Content - Disposition: form - data;
name = "foo";
filename = "foo"

files = {
      'foo': (None, 'bar')
   } >>>
   print(requests.Request('POST', '', files = files).prepare().body.decode('utf8'))
Content - Disposition: form - data;
name = "foo"


There is also the excellent requests-toolbelt project, which includes advanced Multipart support. It takes field definitions in the same format as the files parameter, but unlike requests, it defaults to not setting a filename parameter. In addition, it can stream the request from open file objects, where requests will first construct the request body in memory:

from requests_toolbelt.multipart.encoder
import MultipartEncoder

mp_encoder = MultipartEncoder(
   fields = {
      'foo': 'bar',
      # plain file object,
      no filename or mime type produces a
      # Content - Disposition header with just the part name 'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
r =
   data = mp_encoder, # The MultipartEncoder is posted as data, don 't use files=...!
   # The MultipartEncoder provides the content - type header with the boundary:
   headers = {
      'Content-Type': mp_encoder.content_type

In short, the files parameter takes a dictionary with the key being the name of the form field and the value being either a string or a 2, 3 or 4-length tuple, as described in the section POST a Multipart-Encoded File in the Requests quickstart:

>>> url = '' >>>
   files = {
      'file': ('report.xls', open('report.xls', 'rb'), 'application/', {
         'Expires': '0'

In the above, the tuple is composed as follows:

(filename, data, content_type, headers)

If the value is just a string, the filename will be the same as the key, as in the following:

>>> files = {
   'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'

Content - Disposition: form - data;
name = "obvius_session_id";
filename = "obvius_session_id"
Content - Type: application / octet - stream

72 c2b6f406cdabd578c5fd7598557c52

From the original requests source:

def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.

    :param files: (optional) Dictionary of ``'name': file-like-objects``
        (or ``{'name': file-tuple}``) for multipart encoding upload.
        ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``,
        3-tuple ``('filename', fileobj, 'content_type')``
        or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``,
        where ``'content-type'`` is a string
        defining the content type of the given file
        and ``custom_headers`` a dict-like object 
        containing additional headers to add for the file.

Based on the above, the simplest multipart form request that includes both files to upload and form fields will look like this:

import requests

multipart_form_data = {
   'upload': ('', open('', 'rb')),
   'action': (None, 'store'),
   'path': (None, '/path1')

response ='', files = multipart_form_data)


If you need to post multiple fields with the same name then instead of a dictionary you can define your payload as a list (or a tuple) of tuples:

multipart_form_data = (
   ('file2', ('', open('', 'rb'))),
   ('action', (None, 'store')),
   ('path', (None, '/path1')),
   ('path', (None, '/path2')),
   ('path', (None, '/path3')),

If you need to send multiple fields with the same name, or if the order of form fields is important, then a tuple or a list can be used instead of a dictionary:

multipart_data = MultipartEncoder(
   fields = (
      ('action', 'ingest'),
      ('item', 'spam'),
      ('item', 'sausage'),
      ('item', 'eggs'),

Here is the simple code snippet to upload a single file with additional parameters using requests:

url = 'https://<file_upload_url>'
fp = '/Users/jainik/Desktop/data.csv'

files = {'file': open(fp, 'rb')}
payload = {'file_id': '1234'}

response = requests.put(url, files=files, data=payload, verify=False)

You need to use the name attribute of the upload file that is in the HTML of the site. Example:

autocomplete = "off"
name = "image" >


import requests

site = ''
# the site where you upload the file
filename = 'image.jpg'
# name example

Here, in the place of image, add the name of the upload file in HTML

up = {
   'image': (filename, open(filename, 'rb'), "multipart/form-data")

Then start the request

request =, files = up, data = data)

You can print out the Content-Type header of the request to verify the above using the example given below, which shows how to upload multiple files (or a single file) with (optionally) the same key (i.e., 'files' in the case below), as well as with optional form data (i.e., data=form_data). The documentation on how to POST single and multiple files can be found here and here, respectively. In case you need to upload large files without reading them into memory, have a look at Streaming Uploads. For the server side - in case you need one - please have a look at this answer, from which the code snippet below has been taken, and which uses FastAPI web framework.

import requests

url = ''
files = [('files', open('test_files/a.txt', 'rb')), ('files', open('test_files/b.txt', 'rb'))]
#file = {
   'file': open('test_files/a.txt', 'rb')
for sending a single file
form_data = {
   "name": "foo",
   "point": 0.13,
   "is_accepted": False
resp = = url, data = form_data, files = files)

Suggestion : 2

In this tutorial we'll demonstrate how to upload a file from a Python server to another server by sending a POST request with multipart/form-data using the Python requests library.,The handle_form() of our flask application receives the posted file but doesn't save it. Instead, we'll use the requests library to upload it to the django server.,Now, let's proceed to create the uploading Python server that will make use of the Requests library to send a POST requests to the endpoint for uploading a file between two servers. ,Note: Typically we upload files from a client to a server but in this tutorial, we'll see how we can upload files from a server to another web server using Python and the Requests library.

$ python3 - m venv.env
$ source.env / bin / activate
$ git clone https: // server2
   $ cd server2
$ pip install - r requirments.txt
$ python makemigrations
$ python migrate
$ python runserver
$ pip install requests
$ pip install flask
import os
from flask
import Flask, request, render_template
import requests

app = Flask(__name__)

@app.route('/handle_form', methods = ['POST'])
def handle_form():
   print("Posted file: {}".format(request.files['file']))
file = request.files['file']
return ""

def index():
   return render_template("index.html");

if __name__ == "__main__": = '', port = 8080, debug = True)

Suggestion : 3

In this chapter, we will upload a file using request and read the contents of the file uploaded. We can do it using the files param as shown in the example below.,Requests - Web Scraping using Requests,It is also possible to send the contents of the file as shown below−,We make use of cookies to improve our user experience. By using this website, you agree with our Cookies Policy. Agree Learn more


import requests
myurl = ''
files = {
   'file': open('test.txt', 'rb')
getdata =, files = files)


File upload test using Requests


E: \prequests > python {
   "args": {},
   "data": "",
   "files": {
      "file": "File upload test using Requests"
   "form": {},
   "headers": {
      "Accept": "*/*",
      "Accept-Encoding": "gzip, deflate",
      "Content-Length": "175",
      "Content-Type": "multipart/form-data; 
      boundary = 28 aee3a9d15a3571fb80d4d2a94bfd33 ",
      "Host": "",
      "User-Agent": "python-requests/2.22.0"
   "json": null,
   "origin": ",",
   "url": ""