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)

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.


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!
| improve this answer | |
  • I edited my answer to include a link to my restapi repo on GitHub. This provides a much easier interface. Once you make a reference to a FeatureLayer, you can simply pass in an OID and path to an attachment when calling the addAttachment method. – crmackey May 12 '15 at 17:22
  • Beautiful! Thank you very much for the help. I do my best to read the ArcGIS REST API docs, but found very little guidance. Your resapi repo is a much-needed resource; I'm looking forward to exploring it. – Spatial Austin May 12 '15 at 17:39
  • I agree, the help on adding attachments was not very useful. I just happened to get lucky and find the Multi-Part Encoded file help in the requests documentation. If you haven't used Fiddler, I would recommend it. Very useful for inspecting web traffic, especially when making calls with Python as there is no web interface. – crmackey May 12 '15 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.