How to Send Multipart/Form-Data Requests in Python with requests
Sending data using multipart/form-data encoding is essential for file uploads and submitting complex forms via HTTP POST requests.
This guide explores how to send multipart/form-data requests using the popular requests library in Python, covering scenarios with and without file uploads, and introducing the requests-toolbelt for more advanced control.
Sending Multipart/Form-Data with the files Parameter
The requests library automatically uses multipart/form-data encoding when you provide the files argument to requests.post().
Sending Data Without Actual Files
You can use the files parameter even if you're not uploading files. This forces the Content-Type header to multipart/form-data.
import requests
from pprint import pprint
url = 'https://httpbin.org/post'
response = requests.post(
url,
files={'id': '1', 'site': 'tutorialreference.com'}, # Use files param for multipart
timeout=30
)
print(f"Status Code: {response.status_code}")
if response.ok:
# Print headers to verify Content-Type
pprint(response.json().get('headers'))
Output:
Status Code: 200
{'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate',
'Content-Length': '...',
'Content-Type': 'multipart/form-data; boundary=...', # Correct header
'Host': 'httpbin.org', ... }
- The
filesparameter can be used to send any data using multipart/form-data encoding.
Do not manually set the Content-Type header when using the files parameter. requests handles setting the correct Content-Type including the necessary boundary parameter.
Sending Files
To upload a file, provide a file object opened in binary read mode ('rb') within the files dictionary:
import requests
url = 'https://httpbin.org/post'
try:
# Assume 'data.json' exists in the same directory
with open('data.json', 'rb') as f:
files_to_upload = {'file': f}
response = requests.post(url, files=files_to_upload, timeout=30)
print(response.text)
print(f"Status Code: {response.status_code}")
except FileNotFoundError:
print("Error: data.json not found.")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
Explicitly Setting Filename, Content-Type, and Headers
For more control over file uploads, you can provide a tuple as the value in the files dictionary. The tuple format allows specifying (filename, file_object, content_type, custom_headers).
import requests
url = 'https://httpbin.org/post'
try:
# Assume 'example.xlsx' exists
with open('example.xlsx', 'rb') as f:
files_spec = {
'file': (
'custom_filename.xlsx', # Custom filename
f, # File object
'application/vnd.ms-excel', # Specific Content-Type
{'Expires': '0'} # Custom headers
)
}
response = requests.post(url, files=files_spec, timeout=30)
print(response.text)
print(f"Status Code: {response.status_code}")
except FileNotFoundError:
print("Error: example.xlsx not found.")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
- Plain Text Fields: To send regular form fields alongside files using the
filesparameter structure, set the filename part of the tuple toNone:files_with_text = {
'session_id': (None, 'some_session_value'), # Plain text field
'upload': ('report.txt', open('report.txt', 'rb')) # File field
}
# response = requests.post(url, files=files_with_text) - String as File Content: You can also provide a string directly as the file content:
files_string_content = {
'file': (
'example.csv',
'some,data,to,send\nanother,row,to,send\n' # String content
)
}
# response = requests.post(url, files=files_string_content)
Sending Multipart/Form-Data with requests-toolbelt
The requests-toolbelt library offers the MultipartEncoder for more complex scenarios and streaming uploads.
Installing requests-toolbelt
pip install requests-toolbelt
# or with pip3
pip3 install requests-toolbelt
Using MultipartEncoder
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
url = 'https://httpbin.org/post'
try:
# Assume 'example.xlsx' exists
with open('example.xlsx', 'rb') as f:
multipart_data = MultipartEncoder(
fields={
# Plain text fields
'field1': 'value1',
'field2': 'value2',
# File upload field (filename, file_object, content_type)
'file': ('custom_name.xlsx', f, 'application/vnd.ms-excel')
}
)
response = requests.post(
url,
data=multipart_data, # Pass encoder to 'data'
headers={'Content-Type': multipart_data.content_type}, # Set header from encoder
timeout=30
)
print(response.text)
print(f"Status Code: {response.status_code}")
except FileNotFoundError:
print("Error: example.xlsx not found.")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
- Create a
MultipartEncoderinstance, defining fields with their names, values, and optional content types. - Pass the
MultipartEncoderobject to thedataparameter ofrequests.post(). - Crucially, set the
Content-Typeheader usingmultipart_data.content_type.
Conclusion
This guide demonstrated how to send multipart/form-data requests using Python's requests library.
You learned the primary method using the files parameter for both simple data and file uploads, how to customize file details using tuples, and how to use the requests-toolbelt library for more advanced multipart encoding. Choosing the right method depends on the complexity of the data and files you need to send.