Select to view content in your preferred language

Adding multiple fields to hosted feature layer

603
6
Jump to solution
03-05-2025 04:26 PM
JustinWolff
Regular Contributor

I'm attempting to add new fields to a hosted feature layer if they don't already exist.  Currently my code will add the first field in the list (dictionary), but then fails with the message:

Exception: Unable to add feature service layer definition.
Invalid definition for System.Collections.Generic.List`1[ESRI.ArcGIS.SDS.FieldInfo]

Object reference not set to an instance of an object.

(Error Code: 400)

If it's run a second time it does not add the second field and gives the same error.  I added the sleep thinking it may help but it doesn't.  Any suggestions appreciated.  Thanks.

 

from arcgis.gis import GIS
from arcgis.features import FeatureLayer
import time

username = ''
password = ''

gis = GIS("<url>", username, password, verify_cert=False)

item_id = "<item_id>"

feature_layer_item = gis.content.get(item_id)

feature_layer = FeatureLayer.fromitem(feature_layer_item)
#feature_layer = FeatureLayer.fromitem(feature_url)

fields = feature_layer.properties.fields

existing_field_names = [field.name for field in fields]

new_fields = [
    {"name":"newfield1", "alias": "New Field 1","type": "esriFieldTypeInteger"},
    {"name":"newfield2", "alias": "New Field 2","type":"esriFieldtypeInteger"},
    {"name":"newfield3", "alias": "New Field 3","type":"esriFieldtypeInteger"}
    ]

fields_to_add_list = [] # this is named 'list' but is actually a dictionary
for new_field in new_fields:
    if new_field["name"] not in existing_field_names:
        fields_to_add_list.append(new_field)
        print(f"Field '{new_field['name']}' will be added.")
    else:
        print(f"Field '{new_field['name']}' already exists.")

for field_to_add in fields_to_add_list:
    print(field_to_add)
    feature_layer.manager.add_to_definition({"fields":[field_to_add]})
    time.sleep(20)

 

0 Kudos
1 Solution

Accepted Solutions
Clubdebambos
MVP Regular Contributor

Hi @JustinWolff,

I was able to reproduce your error and fix it. Add in the full field definitions as per below. 

 

from arcgis.gis import GIS
from arcgis.features import FeatureLayer

username = ''
password = ''

gis = GIS("<url>", username, password, verify_cert=False)

item_id = "<item_id>"

feature_layer_item = gis.content.get(item_id)

feature_layer = FeatureLayer.fromitem(feature_layer_item)

fields = feature_layer.properties.fields

existing_field_names = [field.name for field in fields]

## DEFINE THE FIELDS
new_fields = [
    {
        "name": "newfield1",
        "type": "esriFieldTypeInteger",
        "actualType": "int",
        "alias": "New Field 1",
        "sqlType": "sqlTypeInteger",
        "nullable": True,
        "editable": True
    },
    {
        "name": "newfield2",
        "type": "esriFieldTypeInteger",
        "actualType": "int",
        "alias": "New Field 2",
        "sqlType": "sqlTypeInteger",
        "nullable": True,
        "editable": True
    },
    {
        "name": "newfield3",
        "type": "esriFieldTypeInteger",
        "actualType": "int",
        "alias": "New Field 3",
        "sqlType": "sqlTypeInteger",
        "nullable": True,
        "editable": True
    }
]

## REMOVE ANY FIELDS FROM THE LIST THAT ARE ALREADY IN THE FEATURE LAYER
new_fields = [field_info for field_info in new_fields if field_info["name"] not in existing_field_names]

## ADD THE NEW FIELDS
feature_layer.manager.add_to_definition({"fields":new_fields})

 

I hope that helps.

All the best,

Glen

~ learn.finaldraftmapping.com

View solution in original post

6 Replies
DavidSolari
MVP Regular Contributor

Instead of running multiple calls to add_to_definition does doing every field in the fields_to_add_list list work better? I.e.:

feature_layer.manager.add_to_definition({"fields": fields_to_add_list})
0 Kudos
JustinWolff
Regular Contributor

That gives the same error, except it doesn't add the first field, when left out of brackets:

feature_layer.manager.add_to_definition({"fields":fields_to_add_list})

And does not create the first field when placed in brackets:

feature_layer.manager.add_to_definition({"fields":[fields_to_add_list]})

but gives a bit different error:

Exception: Unable to add feature service layer definition.
Invalid definition for System.Collections.Generic.List`1[ESRI.ArcGIS.SDS.FieldInfo]
Unable to cast object of type 'System.Object[]' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'.
(Error Code: 400)

0 Kudos
JustinWolff
Regular Contributor

and if I use field_to_add outside of any brackets it completes without any errors but doesn't add any fields

feature_layer.manager.add_to_definition({"fields":field_to_add})

with the print statements as they currently are:

Field 'newfield1' will be added.
Field 'newfield2' will be added.
Field 'newfield3' will be added.
[{'name': 'newfield1', 'alias': 'New Field 1', 'type': 'esriFieldTypeInteger'}, {'name': 'newfield2', 'alias': 'New Field 2', 'type': 'esriFieldtypeInteger'}, {'name': 'newfield3', 'alias': 'New Field 3', 'type': 'esriFieldtypeInteger'}]
{'name': 'newfield1', 'alias': 'New Field 1', 'type': 'esriFieldTypeInteger'}
{'name': 'newfield2', 'alias': 'New Field 2', 'type': 'esriFieldtypeInteger'}
{'name': 'newfield3', 'alias': 'New Field 3', 'type': 'esriFieldtypeInteger'}

Am I missing something in the field definition?

0 Kudos
Clubdebambos
MVP Regular Contributor

Hi @JustinWolff,

I was able to reproduce your error and fix it. Add in the full field definitions as per below. 

 

from arcgis.gis import GIS
from arcgis.features import FeatureLayer

username = ''
password = ''

gis = GIS("<url>", username, password, verify_cert=False)

item_id = "<item_id>"

feature_layer_item = gis.content.get(item_id)

feature_layer = FeatureLayer.fromitem(feature_layer_item)

fields = feature_layer.properties.fields

existing_field_names = [field.name for field in fields]

## DEFINE THE FIELDS
new_fields = [
    {
        "name": "newfield1",
        "type": "esriFieldTypeInteger",
        "actualType": "int",
        "alias": "New Field 1",
        "sqlType": "sqlTypeInteger",
        "nullable": True,
        "editable": True
    },
    {
        "name": "newfield2",
        "type": "esriFieldTypeInteger",
        "actualType": "int",
        "alias": "New Field 2",
        "sqlType": "sqlTypeInteger",
        "nullable": True,
        "editable": True
    },
    {
        "name": "newfield3",
        "type": "esriFieldTypeInteger",
        "actualType": "int",
        "alias": "New Field 3",
        "sqlType": "sqlTypeInteger",
        "nullable": True,
        "editable": True
    }
]

## REMOVE ANY FIELDS FROM THE LIST THAT ARE ALREADY IN THE FEATURE LAYER
new_fields = [field_info for field_info in new_fields if field_info["name"] not in existing_field_names]

## ADD THE NEW FIELDS
feature_layer.manager.add_to_definition({"fields":new_fields})

 

I hope that helps.

All the best,

Glen

~ learn.finaldraftmapping.com
JustinWolff
Regular Contributor

Thanks Glen, that works well.  As a follow-on, my test data only has one layer [0].  I'll have other situations where there are multiple sublayers.  I'm a bit confused how to use gis.content to return the separate layers.  Any help pointing me in the right direction is appreciated.  Thanks again.

0 Kudos
Clubdebambos
MVP Regular Contributor

Hi @JustinWolff,

The below will help. A Feature Service Item (FeatureLayerCollection) has a property called layers that returns a list of FeatureLayer objects for the service. You can iterate over these or access via indexing.

from arcgis import GIS

## acess ArcGIS Online
agol = GIS("home")

## get the Feature Service as an Item object
item = agol.content.get("FS_ITEM_ID")

## print all feature layer
## note: returns a list of FeatureLayer objects
print(item.layers)

## get the index and name for each layer
for index, fl in enumerate(item.layers):
    print(index, fl.properties.name)

## access via index
fl = item.layers[1]
print(fl)

 

~ learn.finaldraftmapping.com