[GIS] Unable to add attachment to ArcGIS Online feature service using Python and REST API

arcgis-onlineattachmentspythonrequest

I am attempting to use Python to add attachments to an ArcGIS Online hosted feature service, but I'm getting an 'Unable to add attachment to the feature.' message when I run the following code:

import requests 

objectId = '158'
attachUrl = "http://services.arcgis.com/abcdefg/FeatureServer/0/%s/addAttachment" %objectId
files = {'file': open('myAttachment.pdf', 'rb')}
params = { "token": token, "f": "json", "files": files}

r = requests.post(attachUrl, params)
r.text

The result:

u'{"error":{"code":400,"message":"","details":["Unable to add attachment to the feature."]}}'

I have verfied that I'm using a valud url, objectID, and token.

I believe the issue is with the syntax I'm using to make the multipart post request, but I'm new to requests.py and to programmatic file uploads.

Best Answer

You were very close! This was quite tricky actually as the ArcGIS REST API documentation didn't explain much. According to the requests docs, you can explicitly set the content headers. This worked for me:

import requests
import os
token = 'K6ZZZsf0Xtf...........PLNffN03fWcA..' 
url = 'http://yourserver/arcgis/rest/services/FRLK/FS_TESTING/FeatureServer/0'
attachment = r'L:\NEWP\failed\val\PIC_00001963.pdf'

def add_attachment(url, token, oid, attachment):
    att_url = '{}/{}/addAttachment'.format(url, oid)
    files = {'attachment': (os.path.basename(attachment), open(attachment, 'rb'), 'application/pdf')}
    params = {'token': token,'f': 'json'}
    r = requests.post(att_url, params, files=files)
    return r

f = add_attachment(url, token, 2402, attachment)

The real magic happens right here, which is what the REST API is looking for:

files = {'attachment': (os.path.basename(attachment), open(attachment, 'rb'), 'application/pdf')}

And the Fiddler response/webform:

enter image description here

Also, I have just added this functionality to my restapi repository on GitHub. You can download this and use it to perform all kinds of operations against REST Services.

If you want to go this route, you can add attachments like this:

>>> import restapi
>>> usr = 'ursername'
>>> pw = 'password'
>>> url = 'http://yourserver.com/arcgis/rest/services/Folder/Some_featureService/FeatureServer/0'
>>> pts = restapi.FeatureLayer(url, usr, pw) # only need usr and pw if using token based authentication
>>> attach = r'O:\Pfdata\New Prague\Water\MK3-R012013AFB~files\MK3_00032946.jpg'
>>> r = pts.addAttachment(802, attach) # arguments are OID and path to attachment
{u'success': True, u'objectId': 2001}  #attachment has been succesfully added!
Related Question