<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Update Definition on Layer in Feature Service in Python Questions</title>
    <link>https://community.esri.com/t5/python-questions/update-definition-on-layer-in-feature-service/m-p/1068332#M61367</link>
    <description>&lt;P&gt;You cannot update the field names directly, you need to use a combination of update definition, add to definition and delete from definition to rename columns.&lt;/P&gt;&lt;P&gt;Let's start with the &lt;STRONG&gt;update&lt;/STRONG&gt;&amp;nbsp;call.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;update_def = {
    "fields": [
        {
            "name": "THISisWrong",
            "type": "esriFieldTypeString",
            "alias": "AmazingAlias",
            "length": 256,
            "editable": True,
            "nullable": True,
            "defaultValue": None,
            "description": None,
            "domain": None,
        }
    ]
}
res = flyer.manager.update_definition(update_def)
print(res)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This will update the &lt;STRONG&gt;alias&lt;/STRONG&gt; column, though it doesn't directly answer your question.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Now how can we take say column: ThisIsWrong and Rename it to this_is_wrong? or something like that.&amp;nbsp; You'll have to do it in a few steps:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Add the new field&lt;/LI&gt;&lt;LI&gt;Copy the column data&lt;OL&gt;&lt;LI&gt;If field is uneditable, make it uneditable&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;&lt;LI&gt;drop the old field&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import re
from arcgis.gis import GIS
from arcgis.features import FeatureLayer

def _camelCase_to_underscore(name):
    """PEP8ify name"""
    if name[0].isdigit():
        name = "execute_" + name
    name = name.replace(" ", "_")
    if '_' in name:
        return name.lower()
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

if __name__ == "__main__":
    
    gis = GIS(profile='your_online_profile', verify_cert=False, trust_env=True)
    item = gis.content.get("e0d177f6b2ed4b1db1abe848dfea23f8")
    flyer = item.layers[0]
    
    #
    # Creating Columns with New Names
    #
    unchange_fields = [
        v
        for k, v in dict(flyer.properties).items()
        if k in ['objectIdField', 'globalIdField']
    ]
    rename_fields = [
        dict(fld)
        for fld in flyer.properties.fields
        if fld["type"] not in ('esriFieldTypeOID', 'esriFieldTypeGlobalID')
        or fld['name'] not in (unchange_fields)
    ]
    expressions = []
    delete_exp = {"fields": []}
    add_fields = []
    uneditable = []
    for idx, fld in enumerate(rename_fields):
        if _camelCase_to_underscore(fld["name"]) != fld["name"].lower():
    
            expressions.append(
                {
                    "field": _camelCase_to_underscore(fld["name"]),
                    "sqlExpression": fld["name"],
                }
            )
            delete_exp["fields"].append({"name": fld["name"]})
    
            fld['name'] = _camelCase_to_underscore(fld["name"])
            fld['alias'] = _camelCase_to_underscore(fld["alias"])
            if fld['editable'] == False:
                uneditable.append(fld['name'])
            fld['editable'] = True
            add_fields.append(fld)
        else:
            print(f"Skipping field because it meets the format standards: {fld['name']}")
    
    print("Add the renamed columns")
    
    res = flyer.manager.add_to_definition({"fields": add_fields})
    print(res)
    print("Update the column values")
    job = flyer.calculate(where="1=1", calc_expression=expressions, future=True)
    result = job.result()
    print(result)
 
    # Set fields that are not editable back to original state.
    #
    update_editable = [fld for fld in add_fields if fld['name'] in uneditable]
    if update_editable:
        for fld in update_editable:
            fld['editable'] = True
        update_def = {"fields": update_editable}
    
        res = flyer.manager.update_definition(update_def)
        print(res)
    #  Drop the Old Fields
    #
    print(flyer.manager.delete_from_definition(delete_exp))
    flyer._refresh()
    print([fld['name'] for fld in flyer.properties.fields])&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;It should be noted that this code doesn't handle cases.&amp;nbsp; If you have a field called&amp;nbsp;&lt;STRONG&gt;Editor&lt;/STRONG&gt; the caml casing should be&amp;nbsp;&lt;STRONG&gt;editor&lt;/STRONG&gt;.&amp;nbsp; The underlying database sees the field as the same name and thus can't be renamed.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Tue, 15 Jun 2021 11:38:11 GMT</pubDate>
    <dc:creator>AndrewChapkowski</dc:creator>
    <dc:date>2021-06-15T11:38:11Z</dc:date>
    <item>
      <title>Update Definition on Layer in Feature Service</title>
      <link>https://community.esri.com/t5/python-questions/update-definition-on-layer-in-feature-service/m-p/1067731#M61353</link>
      <description>&lt;P&gt;Have been tinkering with this for the better part of a day and can't figure it out.&amp;nbsp;&lt;/P&gt;&lt;P&gt;I'm calling an API to get a json response containing store locations, which contain the coordinates, then pushing that into a Feature Layer. Esri's implementation of the Spatially Enabled Dataframe's .to_featurelayer has the unfortunate behavior of sanitizing column names, even if the column names are valid to begin with.&lt;/P&gt;&lt;P&gt;The result is that its changing my column names from their original case to snake_case. For example 'storeName' gets changed to 'store_name' when I utilize the .to_featurelayer method to publish the data frame as a feature layer, even though there is absolutely nothing invalid at all about a feature layer with a field named 'storeName'.&lt;/P&gt;&lt;P&gt;Unlike the .to_featureclass method, where sanitize_columns is exposed as a parameter in the method and defaulted to True, meaning you can set it to False to avoid this behavior, sanitize_columns is defaulted to to True in the .to_featurelayer method and is not exposed as a parameter so there is no way to avoid it.&lt;/P&gt;&lt;P&gt;As a result, I'm trying to go back and update the column names using the update_definition method on the feature layer manager but I keep getting one of two errors.&amp;nbsp;&lt;/P&gt;&lt;P&gt;The first approach I took:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from arcgis.features import FeatureLayer
featureLayer =gis.content.get("c952e9e257bd4fc887be2934291548cb")
lyr = featureLayer.layers[0]
lyr.properties
originalDefinition = lyr.properties
# Get the fields array
originalFields = originalDefinition["fields"]
newFields = originalFields.copy()
for f in newFields:
    if "_" in f["name"]:
        newFieldName = f["name"].split("_")[0].lower()+f["name"].split("_")[1].title()
        f["name"] = newFieldName
#newFields
print('"fields": ' + json.dumps(newFields))
lyr.manager.update_definition('"fields": ' + json.dumps(newFields))&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Fails with:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
&amp;lt;ipython-input-28-34cef8ca738c&amp;gt; in &amp;lt;module&amp;gt;
     13 #newFields
     14 print('"fields": ' + json.dumps(newFields))
---&amp;gt; 15 lyr.manager.update_definition('"fields": ' + json.dumps(newFields))

/opt/conda/lib/python3.7/site-packages/arcgis/features/managers.py in update_definition(self, json_dict)
   2002         u_url = self._url + "/updateDefinition"
   2003 
-&amp;gt; 2004         res = self._con.post(u_url, params)
   2005         self.refresh()
   2006         return res

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in post(self, path, params, files, **kwargs)
    718                                      file_name=file_name,
    719                                      try_json=try_json,
--&amp;gt; 720                                      force_bytes=kwargs.pop('force_bytes', False))
    721     #----------------------------------------------------------------------
    722     def put(self, url, params=None, files=None, **kwargs):

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in _handle_response(self, resp, file_name, out_path, try_json, force_bytes)
    512                     return data
    513                 errorcode = data['error']['code'] if 'code' in data['error'] else 0
--&amp;gt; 514                 self._handle_json_error(data['error'], errorcode)
    515             return data
    516         else:

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in _handle_json_error(self, error, errorcode)
    534 
    535         errormessage = errormessage + "\n(Error Code: " + str(errorcode) +")"
--&amp;gt; 536         raise Exception(errormessage)
    537     #----------------------------------------------------------------------
    538     def post(self,

Exception: Unable to update feature service layer definition.
Object reference not set to an instance of an object.
(Error Code: 400)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Kinda makes sense. Maybe I need to instantiate a FeatureLayer object on the actual layer...Let's try that:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;featureLayer =gis.content.get("c952e9e257bd4fc887be2934291548cb")
lyr = FeatureLayer(featureLayer.layers[0])
originalDefinition = lyr.properties
# Get the fields array
originalFields = originalDefinition["fields"]
newFields = originalFields.copy()
for f in newFields:
    if "_" in f["name"]:
        newFieldName = f["name"].split("_")[0].lower()+f["name"].split("_")[1].title()
        f["name"] = newFieldName
newFields
print('"fields": ' + json.dumps(newFields))
#lyr.manager.update_definition('"fields": ' + json.dumps(newFields))&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;But it fails with:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
/opt/conda/lib/python3.7/site-packages/arcgis/gis/__init__.py in _hydrate(self)
  11481                     if isinstance(self._con, Connection):
&amp;gt; 11482                         self._lazy_token = self._con.generate_portal_server_token(serverUrl=self._url)
  11483                     else:

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in generate_portal_server_token(self, serverUrl, expiration)
   1313             resp = self.post(path=self._token_url, postdata=postdata,
-&amp;gt; 1314                              ssl=True, add_token=False)
   1315         if isinstance(resp, dict) and resp:

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in post(self, path, params, files, **kwargs)
    719                                      try_json=try_json,
--&amp;gt; 720                                      force_bytes=kwargs.pop('force_bytes', False))
    721     #----------------------------------------------------------------------

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in _handle_response(self, resp, file_name, out_path, try_json, force_bytes)
    513                 errorcode = data['error']['code'] if 'code' in data['error'] else 0
--&amp;gt; 514                 self._handle_json_error(data['error'], errorcode)
    515             return data

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in _handle_json_error(self, error, errorcode)
    535         errormessage = errormessage + "\n(Error Code: " + str(errorcode) +")"
--&amp;gt; 536         raise Exception(errormessage)
    537     #----------------------------------------------------------------------

Exception: Unable to generate token.
'username' must be specified.
'password' must be specified.
'referer' must be specified.
(Error Code: 400)

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
&amp;lt;ipython-input-27-77bf06c45026&amp;gt; in &amp;lt;module&amp;gt;
      2 featureLayer =gis.content.get("c952e9e257bd4fc887be2934291548cb")
      3 lyr = FeatureLayer(featureLayer.layers[0], gis=gis)
----&amp;gt; 4 lyr.properties
      5 originalDefinition = lyr.properties
      6 # Get the fields array

/opt/conda/lib/python3.7/site-packages/arcgis/gis/__init__.py in properties(self)
  11460             return self._lazy_properties
  11461         else:
&amp;gt; 11462             self._hydrate()
  11463             return self._lazy_properties
  11464 

/opt/conda/lib/python3.7/site-packages/arcgis/gis/__init__.py in _hydrate(self)
  11507                     # try as a public server
  11508                     self._lazy_token = None
&amp;gt; 11509                     self._refresh()
  11510 
  11511                 except HTTPError as httperror:

/opt/conda/lib/python3.7/site-packages/arcgis/gis/__init__.py in _refresh(self)
  11450                     dictdata = self._con.get(self.url, params)
  11451                 else:
&amp;gt; 11452                     raise e
  11453 
  11454         self._lazy_properties = PropertyMap(dictdata)

/opt/conda/lib/python3.7/site-packages/arcgis/gis/__init__.py in _refresh(self)
  11443         else:
  11444             try:
&amp;gt; 11445                 dictdata = self._con.post(self.url, params, token=self._lazy_token)
  11446             except Exception as e:
  11447                 if hasattr(e, 'msg') and e.msg == "Method Not Allowed":

/opt/conda/lib/python3.7/site-packages/arcgis/gis/_impl/_con/_connection.py in post(self, path, params, files, **kwargs)
    619         try_json = kwargs.pop("try_json", True)
    620         add_token = kwargs.pop('add_token', True)
--&amp;gt; 621         if url.find('://') == -1:
    622             url = self._baseurl + url
    623         if kwargs.pop("ssl", False) or self._all_ssl:

AttributeError: 'FeatureLayer' object has no attribute 'find'&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I don't understand why I would need to authenticate with credentials manually here or even how I would. I have a connection to a GIS object and even passing that in as the gis parameter on the instantiation of the FeatureLayer object at line 3 doesn't change result.&lt;/P&gt;&lt;P&gt;I also tried using FeatureCollection but got the same result in both approaches.&lt;/P&gt;&lt;P&gt;Help or insight appreciated.&lt;/P&gt;</description>
      <pubDate>Sun, 13 Jun 2021 17:41:33 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/update-definition-on-layer-in-feature-service/m-p/1067731#M61353</guid>
      <dc:creator>JohnMDye</dc:creator>
      <dc:date>2021-06-13T17:41:33Z</dc:date>
    </item>
    <item>
      <title>Re: Update Definition on Layer in Feature Service</title>
      <link>https://community.esri.com/t5/python-questions/update-definition-on-layer-in-feature-service/m-p/1068332#M61367</link>
      <description>&lt;P&gt;You cannot update the field names directly, you need to use a combination of update definition, add to definition and delete from definition to rename columns.&lt;/P&gt;&lt;P&gt;Let's start with the &lt;STRONG&gt;update&lt;/STRONG&gt;&amp;nbsp;call.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;update_def = {
    "fields": [
        {
            "name": "THISisWrong",
            "type": "esriFieldTypeString",
            "alias": "AmazingAlias",
            "length": 256,
            "editable": True,
            "nullable": True,
            "defaultValue": None,
            "description": None,
            "domain": None,
        }
    ]
}
res = flyer.manager.update_definition(update_def)
print(res)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This will update the &lt;STRONG&gt;alias&lt;/STRONG&gt; column, though it doesn't directly answer your question.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Now how can we take say column: ThisIsWrong and Rename it to this_is_wrong? or something like that.&amp;nbsp; You'll have to do it in a few steps:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;Add the new field&lt;/LI&gt;&lt;LI&gt;Copy the column data&lt;OL&gt;&lt;LI&gt;If field is uneditable, make it uneditable&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;&lt;LI&gt;drop the old field&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;import re
from arcgis.gis import GIS
from arcgis.features import FeatureLayer

def _camelCase_to_underscore(name):
    """PEP8ify name"""
    if name[0].isdigit():
        name = "execute_" + name
    name = name.replace(" ", "_")
    if '_' in name:
        return name.lower()
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

if __name__ == "__main__":
    
    gis = GIS(profile='your_online_profile', verify_cert=False, trust_env=True)
    item = gis.content.get("e0d177f6b2ed4b1db1abe848dfea23f8")
    flyer = item.layers[0]
    
    #
    # Creating Columns with New Names
    #
    unchange_fields = [
        v
        for k, v in dict(flyer.properties).items()
        if k in ['objectIdField', 'globalIdField']
    ]
    rename_fields = [
        dict(fld)
        for fld in flyer.properties.fields
        if fld["type"] not in ('esriFieldTypeOID', 'esriFieldTypeGlobalID')
        or fld['name'] not in (unchange_fields)
    ]
    expressions = []
    delete_exp = {"fields": []}
    add_fields = []
    uneditable = []
    for idx, fld in enumerate(rename_fields):
        if _camelCase_to_underscore(fld["name"]) != fld["name"].lower():
    
            expressions.append(
                {
                    "field": _camelCase_to_underscore(fld["name"]),
                    "sqlExpression": fld["name"],
                }
            )
            delete_exp["fields"].append({"name": fld["name"]})
    
            fld['name'] = _camelCase_to_underscore(fld["name"])
            fld['alias'] = _camelCase_to_underscore(fld["alias"])
            if fld['editable'] == False:
                uneditable.append(fld['name'])
            fld['editable'] = True
            add_fields.append(fld)
        else:
            print(f"Skipping field because it meets the format standards: {fld['name']}")
    
    print("Add the renamed columns")
    
    res = flyer.manager.add_to_definition({"fields": add_fields})
    print(res)
    print("Update the column values")
    job = flyer.calculate(where="1=1", calc_expression=expressions, future=True)
    result = job.result()
    print(result)
 
    # Set fields that are not editable back to original state.
    #
    update_editable = [fld for fld in add_fields if fld['name'] in uneditable]
    if update_editable:
        for fld in update_editable:
            fld['editable'] = True
        update_def = {"fields": update_editable}
    
        res = flyer.manager.update_definition(update_def)
        print(res)
    #  Drop the Old Fields
    #
    print(flyer.manager.delete_from_definition(delete_exp))
    flyer._refresh()
    print([fld['name'] for fld in flyer.properties.fields])&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;It should be noted that this code doesn't handle cases.&amp;nbsp; If you have a field called&amp;nbsp;&lt;STRONG&gt;Editor&lt;/STRONG&gt; the caml casing should be&amp;nbsp;&lt;STRONG&gt;editor&lt;/STRONG&gt;.&amp;nbsp; The underlying database sees the field as the same name and thus can't be renamed.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 15 Jun 2021 11:38:11 GMT</pubDate>
      <guid>https://community.esri.com/t5/python-questions/update-definition-on-layer-in-feature-service/m-p/1068332#M61367</guid>
      <dc:creator>AndrewChapkowski</dc:creator>
      <dc:date>2021-06-15T11:38:11Z</dc:date>
    </item>
  </channel>
</rss>

