Learn how to add, update, and delete features in a hosted feature layer.
In this tutorial you will use the Point, Feature, and FeatureLayer classes to create new features in an existing feature layer. The data will be stored in your own ArcGIS Portal and can be used in other tutorials and projects.
Prerequisites
The ArcGIS API for Python tutorials use Jupyter Notebooks to execute Python code. If you are new to this environment, please see the guide to install the API and use notebooks locally.
Steps
Prepare data
- You will access the
Trailheads
feature layer created in the Import data tutorial. You can also create a blank online layer using your portal, see the Define a new feature layer tutorial for detailed steps.
Import modules and log in
-
Import
GIS
from thearcgis.gis
module and use it to log in to your portal using an ArcGIS Location Platform account, ArcGIS Online account, or ArcGIS Enterprise account.Use dark colors for code blocks from arcgis.gis import GIS from arcgis.geometry import Point from arcgis.features import Feature import random portal = GIS(username="username") print(f"connected to {portal.properties.name} as {portal.properties.user.username}")
Access the feature layer
-
Use the
content
property to search for theTrailheads
feature service you created in the Import Data tutorial.Use dark colors for code blocks from arcgis.gis import GIS from arcgis.geometry import Point from arcgis.features import Feature import random portal = GIS(username="username") print(f"connected to {portal.properties.name} as {portal.properties.user.username}") query = 'title: "Trailheads*" AND type: "Feature Service"' search_results = gis.content.search(query=query, max_items=10)
-
Find the
Trailheads
feature service from the list of results, and display the URL of the item. The index for the specific layer may be different in your organization.Use dark colors for code blocks query = 'title: "Trailheads*" AND type: "Feature Service"' search_results = gis.content.search(query=query, max_items=10) trailheads_item = search_results[0] trailheads_item.url
-
Access the list of layers in the feature service, and assign the trailheads feature layer to a new variable named
points
._layer Use dark colors for code blocks query = 'title: "Trailheads*" AND type: "Feature Service"' search_results = gis.content.search(query=query, max_items=10) trailheads_item = search_results[0] trailheads_item.url points_layer = trailheads_item.layers[0] points_layer.properties.name
-
List the field names and field types by enumerating through the fields using the layer
properties
. This will give us insight into which fields we want to use when editing.Use dark colors for code blocks trailheads_item = search_results[0] trailheads_item.url points_layer = trailheads_item.layers[0] points_layer.properties.name for field in points_layer.properties['fields']: print(f"Name: {field['name']}, type: {field['type']}")
-
Call the
query
method using thereturn
parameter to return the current number of features contained in the feature layer._count _only Use dark colors for code blocks trailheads_item = search_results[0] trailheads_item.url points_layer = trailheads_item.layers[0] points_layer.properties.name for field in points_layer.properties['fields']: print(f"Name: {field['name']}, type: {field['type']}") current_feature_count = points_layer.query(where="1=1", return_count_only=True) current_feature_count
Create an edit function
-
Write a reusable function that returns
feature
objects given an inputpoint
geometry. You will use thegeometry
module to create aPoint
geometry object and thefeatures
module to create aFeature
object. Use therandom
module to generate values to use as values for attributes. Use field names we discovered back in step 6.Use dark colors for code blocks for field in points_layer.properties['fields']: print(f"Name: {field['name']}, type: {field['type']}") current_feature_count = points_layer.query(where="1=1", return_count_only=True) current_feature_count def create_feature(from_point): # create a psuedo random number random_num = random.sample(range(-32678, 32767), 1)[0] # create a new point geometry point = Point({ "x": from_point[0], "y": from_point[1], "spatialReference": {"wkid": 102100} }) # create a new feature object new_feature = Feature( geometry=point, attributes={ "TRL_ID": random_num, "TRL_NAME": f"Trail {random_num}" }) # return the new feature return new_feature
Perform the edit operations
-
Create a list of point geometries to be added to the feature layer.
Use dark colors for code blocks def create_feature(from_point): # create a psuedo random number random_num = random.sample(range(-32678, 32767), 1)[0] # create a new point geometry point = Point({ "x": from_point[0], "y": from_point[1], "spatialReference": {"wkid": 102100} }) # create a new feature object new_feature = Feature( geometry=point, attributes={ "TRL_ID": random_num, "TRL_NAME": f"Trail {random_num}" }) # return the new feature return new_feature # create a list of points to add to the feature layer pts = [ [-13171333.070799998939037, 4042695.321999996900558], [-13242990.358199998736382, 4033735.280599996447563], [-13175934.033300001174212, 4019713.409100003540516], [-13205283.364500001072884, 4024074.358800001442432], [-13240366.94880000129342, 4038035.472000002861023], [-13262797.765900000929832, 4042863.907899998128414], [-13225526.658399999141693, 4047097.181400001049042], [-13198009.883299998939037, 4034317.139899998903275], [-13173824.26300000026822, 4018733.889600001275539], [-13219729.814500000327826, 4024812.550099998712540], [-13168754.60139999911189, 4042368.257200002670288], [-13186098.097899999469519, 4031719.417900003492832], [-13260383.321899998933077, 4043455.122699998319149], [-13204961.706000000238419, 4048183.480999998748302], [-13216203.758700000122190, 4059118.715800002217293], [-13263163.670600000768900, 4050992.630599997937679], [-13187563.843699999153614, 4051919.309100002050400], [-13264305.876699998974800, 4038344.382200002670288], [-13231383.650699999183416, 4050043.688400000333786], [-13216463.800000000745058, 4042839.030299998819828], ]
-
Iterate through each geometry in the array and call the edit function. This will return a list new features.
Use dark colors for code blocks # create a list of points to add to the feature layer pts = [ [-13171333.070799998939037, 4042695.321999996900558], [-13242990.358199998736382, 4033735.280599996447563], [-13175934.033300001174212, 4019713.409100003540516], [-13205283.364500001072884, 4024074.358800001442432], [-13240366.94880000129342, 4038035.472000002861023], [-13262797.765900000929832, 4042863.907899998128414], [-13225526.658399999141693, 4047097.181400001049042], [-13198009.883299998939037, 4034317.139899998903275], [-13173824.26300000026822, 4018733.889600001275539], [-13219729.814500000327826, 4024812.550099998712540], [-13168754.60139999911189, 4042368.257200002670288], [-13186098.097899999469519, 4031719.417900003492832], [-13260383.321899998933077, 4043455.122699998319149], [-13204961.706000000238419, 4048183.480999998748302], [-13216203.758700000122190, 4059118.715800002217293], [-13263163.670600000768900, 4050992.630599997937679], [-13187563.843699999153614, 4051919.309100002050400], [-13264305.876699998974800, 4038344.382200002670288], [-13231383.650699999183416, 4050043.688400000333786], [-13216463.800000000745058, 4042839.030299998819828], ] # iterage through each coordinate in the array and return a list of new features new_features = [] for pt in pts: new_features.append(create_feature(pt)) print(f"{len(new_features)} new feature objects generated")
-
Use the
edit
method to send the list of new features to the feature layer. Then perform another count of features in the feature layer again. The count should increase by twenty._features Use dark colors for code blocks # iterage through each coordinate in the array and return a list of new features new_features = [] for pt in pts: new_features.append(create_feature(pt)) print(f"{len(new_features)} new feature objects generated") # Use the `edit_features` method to send our list of new feature objects to the feature layer edit_result = points_layer.edit_features(adds=new_features) # for a large number of features it is recommended to use the [append]() method. edit_result post_add_feature_count = points_layer.query(where="1=1", return_count_only = True) print(f"post add features count: {post_add_feature_count}")
-
Update an attribute of the features you just created. The add operation will return a result object containing the list of
object
that were successfully updated. Loop through the add results and create an array of attribute objects with a new value and theIds OBJECTID
. Use theedit
again method but use the_features updates
parameter and pass in our list of attribute values.Use dark colors for code blocks # Use the `edit_features` method to send our list of new feature objects to the feature layer edit_result = points_layer.edit_features(adds=new_features) # for a large number of features it is recommended to use the [append]() method. edit_result post_add_feature_count = points_layer.query(where="1=1", return_count_only = True) print(f"post add features count: {post_add_feature_count}") # get the objectid field name from our source layer oid_fld = points_layer.properties.objectIdField update_features = [] for itm in edit_result['addResults']: update_features.append({ "attributes":{ oid_fld:int(itm['objectId']), # update requires an objectid "FEAT_CMNT": "Delete Me" # update an existing field value } }) update_features points_layer.edit_features(updates = update_features)
-
Delete features from the feature layer. Use the
query
method to retrieve the features that were just added as a FeatureSet (as
). Pass these features to the_df=false edit
method, in the_features deletes
parameter. Perform another count, the final count (post
) should equal the_delete _feature _count current
._feature _count Use dark colors for code blocks # get the objectid field name from our source layer oid_fld = points_layer.properties.objectIdField update_features = [] for itm in edit_result['addResults']: update_features.append({ "attributes":{ oid_fld:int(itm['objectId']), # update requires an objectid "FEAT_CMNT": "Delete Me" # update an existing field value } }) update_features points_layer.edit_features(updates = update_features) remove_points = points_layer.query(where="FEAT_CMNT = 'Delete Me'", out_fields="*", as_df=False) points_layer.edit_features(deletes = remove_points) post_delete_feature_count = points_layer.query(where="1=1", return_count_only = True) print(f"post delete feature count: {post_delete_feature_count}") print(f"Start and end counts are equal: {current_feature_count == post_delete_feature_count}")
What's next?
Learn how to use additional functionality in these tutorials: