I am having trouble determining the proper way to use add_to_definition:
https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.managers.html
A sample js dict seems to be here:
https://developers.arcgis.com/rest/services-reference/add-to-definition-feature-service-.htm
This may end up me not being able to determine the appropriate workflow. When I used ArcGIS Pro to publish my feature service the first time, the feature layers were published under one service definition (Map):
I am able to update layers using layer.edit_features, and remove them using featureLayerCollection.manager.delete_from_definition(json_delete_dict).
What I am trying to do is write a json_dict directly to the 'Map' Service Definition. I don't want to publish something separately via item.publish (unless I'm supposed to?):
I want to directly 'append', for lack of a better word, the layer to the service definition in the same way the other layers and data were published the first time:
Is it possible to directly add a layer to a service definition without publishing the item first? Am I off base? If I'm not even close, can someone walk me through the steps to add a layer to a service definition? Is there sample code anywhere (specifically a python add_to_definition json dict)?
Appreciate any and all insight.
I recently got something to work, and it may be of use to you. It uses the requests Python library instead of the ArcGIS Python API (I couldn't get that to work either). I just POST to the addToDefinition tool and it adds a table. Looking through this thread helped me quite a bit. Still working on adding a relationship.
Of course, change type to "Feature Layer" if that's what you want, I've only gotten a table working.
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection
import json
import requests
gis = GIS('https://www.arcgis.com','user','pw')
feature_item = gis.content.get('ITEMID')
flayer = FeatureLayerCollection.fromitem(feature_item)
token = gis._con.token
url = f'{flayer.service.url}/AddToDefinition?token={token}'
print(url)
add_json = ''' {
"layers" : [
{
"name" : "Maintenance_py",
"type" : "Table",
"objectIdField" : "FID",
"fields" : [
{
"name" : "reference",
"type" : "esriFieldTypeGUID",
"alias" : "reference",
"sqlType" : "sqlTypeOther",
"nullable" : false,
"editable" : true,
"length" : 38,
"visible" : true,
"domain" : null,
"defaultValue" : null
},
{
"name" : "MaintDate",
"type" : "esriFieldTypeDate",
"alias" : "Maintenance Date",
"sqlType" : "sqlTypeOther",
"length" : 8,
"nullable" : true,
"editable" : true,
"domain" : null,
"defaultValue" : null
},
{
"name" : "MaintType",
"type" : "esriFieldTypeString",
"actualType" : "nvarchar",
"alias" : "Maintenance Type",
"sqlType" : "sqlTypeNVarchar",
"length" : 256,
"nullable" : true,
"editable" : true,
"visible" : true,
"domain" : null,
"defaultValue" : null
},
{
"name" : "Notes",
"type" : "esriFieldTypeString",
"actualType" : "nvarchar",
"alias" : "Notes",
"sqlType" : "sqlTypeNVarchar",
"length" : 256,
"nullable" : true,
"editable" : true,
"visible" : true,
"domain" : null,
"defaultValue" : null
},
{
"name" : "CreationDate",
"type" : "esriFieldTypeDate",
"alias" : "CreationDate",
"sqlType" : "sqlTypeOther",
"length" : 8,
"nullable" : true,
"editable" : false,
"domain" : null,
"defaultValue" : null
},
{
"name" : "Creator",
"type" : "esriFieldTypeString",
"alias" : "Creator",
"sqlType" : "sqlTypeOther",
"length" : 50,
"nullable" : true,
"editable" : false,
"domain" : null,
"defaultValue" : null
},
{
"name" : "EditDate",
"type" : "esriFieldTypeDate",
"alias" : "EditDate",
"sqlType" : "sqlTypeOther",
"length" : 8,
"nullable" : true,
"editable" : false,
"domain" : null,
"defaultValue" : null
},
{
"name" : "Editor",
"type" : "esriFieldTypeString",
"alias" : "Editor",
"sqlType" : "sqlTypeOther",
"length" : 50,
"nullable" : true,
"editable" : false,
"domain" : null,
"defaultValue" : null
},
{
"name" : "FID",
"type" : "esriFieldTypeOID",
"actualType" : "int",
"alias" : "FID",
"sqlType" : "sqlTypeInteger",
"length" : 4,
"nullable" : false,
"editable" : false,
"domain" : null,
"defaultValue" : null
}
]
}
]
}'''
payload = {
'addToDefinition': add_json,
'async': 'false',
'f': 'json',
'token': token
}
session = requests.Session()
result = session.post(url,data=payload)
print(result)
Hi Ryan appreciate the snippet. I could not figure out how to get a table added and this seems to do just that. I've got to wrap up another project then I'm diving back into this one. Thanks!
I made more progress. I want to change this script so it actually uses the add_to_definition method from the API (since it would probably make my script less verbose), but for now, this works. Below is a modified of my final script (because it's doing something slightly different than what you want), but this snippet might be helpful too.
I haven't tested this exact script, but it should work. Just input the service URL of your table (it has to uploaded to AGOL first, doesn't matter where it is) and the item ID of where you want to add the table. Again, haven't tested this for a feature layer instead of a table.
EDIT: test this on some dummy data first. I've had addToDefinition go wrong before and pretty much delete all my data (but it was okay b/c it was dummy data). The finalized script shouldn't do that, but still test it.
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection, FeatureLayer
import json, requests
url = 'https://www.arcgis.com'
user = 'username'
pw = 'pw'
gis = GIS(url,user,pw)
def build_json(table, name):
# turn PropertyMap type to list of dictionaries (PropertyMap is not JSON
# serializable)
fields = []
for i in table:
d = {}
for k,v in i.items():
d[k] = v
fields.append(d)
# assumes field OBJECTID is your objectIdField
temp_json = json.dumps({'layers':
[{'name':name,
'type': 'Table',
'objectIdField': 'OBJECTID',
'fields': fields}]})
return temp_json
def add_to_definition(origin,add_json,table_name):
token = gis._con.token
flayer = FeatureLayerCollection.fromitem(origin)
url = f'{flayer.service.url}/AddToDefinition?token={token}' # build URL to POST to
payload_add = {
'addToDefinition': add_json,
'async': 'true',
'f': 'json',
'token': token
}
session = requests.Session()
result = session.post(url,data=payload_add)
print(result)
def main():
ago_table = FeatureLayer('URL to your feature layer')
origin = gis.content.get('ID of the feature class you want to add data to')
table_name = ago_table.properties.name
fields = ago_table.properties.fields
add_json = build_json(fields,table_name)
add_to_definition(origin, add_json, table_name)
if __name__ == '__main__':
main()
Hi John,
I'm guessing the problem is just that your input JSON is somehow invalid. I've attached another sample input which will add 3 layers to an existing service (point, line, polygon) - it's too long to include as a dictionary here.
from arcgis import GIS
from arcgis.features import FeatureLayerCollection
conn = GIS("https://www.arcgis.com",
"Hari", "Seldon")
layer_name = "Foundation"
search_results = conn.content.search(layer_name, item_type="Feature Layer")
proper_index = [i for i, s in enumerate(search_results)
if '"' + layer_name + '"' in str(s)]
found_item = search_results[proper_index[0]]
source_flc = FeatureLayerCollection.fromitem(found_item)
add_data = <<< attached data >>>
source_flc.manager.add_to_definition(add)
Note: You could load the attached data using the json library, but you'd need to change True to true, False to false, None to null....
Hope this helps.
To answer your greater question, is your approach the best approach? That depends - you could certainly just overwrite the existing service with your additional layer and be done with the matter without ever having to guess what the JSON should be. It's really up to you how you want to approach the problem.
-Earl
I may end up doing just that. It seemed like a lot of overhead considering the layers update/add/change frequently. If I end up burning too much time on the above add to definition table, I'll just overwrite the whole service.
Thanks!