È necessario utilizzare il files
parametro per inviare una richiesta POST di modulo multipart anche quando non è necessario caricare alcun file.
Dalla fonte delle richieste originali :
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.
La parte rilevante è: file-tuple can be a
2-tuple
, .3-tuple
or a
4-tuple
Sulla base di quanto sopra, la richiesta di modulo multipart più semplice che include sia i file da caricare sia i campi del modulo sarà simile al seguente:
multipart_form_data = {
'file2': ('custom_file_name.zip', open('myfile.zip', 'rb')),
'action': (None, 'store'),
'path': (None, '/path1')
}
response = requests.post('https://httpbin.org/post', files=multipart_form_data)
print(response.content)
☝ Nota None
come primo argomento nella tupla per i campi di testo semplice: si tratta di un segnaposto per il campo nome file che viene utilizzato solo per i caricamenti di file, ma per i campi di testo che passano None
come primo parametro è necessario per l'invio dei dati .
Più campi con lo stesso nome
Se devi pubblicare più campi con lo stesso nome, invece di un dizionario puoi definire il tuo payload come un elenco (o una tupla) di tuple:
multipart_form_data = (
('file2', ('custom_file_name.zip', open('myfile.zip', 'rb'))),
('action', (None, 'store')),
('path', (None, '/path1')),
('path', (None, '/path2')),
('path', (None, '/path3')),
)
API richieste di streaming
Se l'API di cui sopra non è abbastanza pythonic per te, allora considera l'utilizzo di request toolbelt ( pip install requests_toolbelt
) che è un'estensione del modulo di richieste core che fornisce supporto per lo streaming di upload di file e MultipartEncoder che può essere utilizzato al posto di files
, e che consente anche si definisce il payload come dizionario, tupla o elenco.
MultipartEncoder
può essere utilizzato sia per richieste multipart con o senza campi di upload effettivi. Deve essere assegnato al data
parametro.
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
multipart_data = MultipartEncoder(
fields={
# a file upload field
'file': ('file.zip', open('file.zip', 'rb'), 'text/plain')
# plain text fields
'field0': 'value0',
'field1': 'value1',
}
)
response = requests.post('http://httpbin.org/post', data=multipart_data,
headers={'Content-Type': multipart_data.content_type})
Se è necessario inviare più campi con lo stesso nome o se l'ordine dei campi modulo è importante, è possibile utilizzare una tupla o un elenco anziché un dizionario:
multipart_data = MultipartEncoder(
fields=(
('action', 'ingest'),
('item', 'spam'),
('item', 'sausage'),
('item', 'eggs'),
)
)