ArcGIS Pro - Modifying Layer Definition query via ArcPY

3205
8
10-08-2019 07:36 PM
janrykr1
New Contributor II

Let's say I need to add a new statement to an existing Def query to all layers in a group which would like like something like this:

aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Map")[0]
for lyr in m.listLayers():
 if lyr.supports ("longname"):
 parent = lyr.longName.split('\\')
 
 if parent [0] == "Group":
 print (lyr.longName)
  if lyr.supports("DEFINITIONQUERY"):
   oldDefQuery = lyr.definitionQuery
   lyr.definitionQuery = None
   newDefQuery = oldDefQuery + " CODE = 0" 
   lyr.definitionQuery = newDefQuery‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

What happens after running the script is that the old definition query becomes inactive and the newly created query is added and becomes active. However they both remain the same query name and seem to clash with each other so that no feature pass through the query (don't mind the fieldnames):

There seem to be no detailed explanation on the definitionQuery property at Layer—ArcPy | ArcGIS Desktop 

So the questions are: 

  • How to achieve this to work properly:
    • Modify the existing one? - This used to work in ArcMAP
    • Remove the initial query completely and place a new modified query?
  • Is there any documentation on how to control the functions in the definition query tab on layer properties via Arcpy?? 

Thanks heaps!

0 Kudos
8 Replies
FPCWAGIS_Admin
New Contributor III

Did you ever manage to solve this?

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Since I am not sure of the OP's code indentations, I will focus on once you have a reference to a layer:

sql = # Additional WHERE clause to append to existing

lyr_cim = lyr.getDefinition('V2')
cim_ft = lyr_cim.featureTable
defExpName = cim_ft.definitionExpressionName
defExpIdx = next(
    i for
    i,n in
    enumerate(cim_ft.definitionFilterChoices)
    if n.name == defExpName
)
cim_ft.definitionExpression += sql
cim_ft.definitionFilterChoices[defExpIdx] = cim_ft.definitionExpression
lyr.setDefinition(lyr_cim)
janrykr1
New Contributor II

No, haven't solved this entirely.  The easiest workaround was to go back to ArcMap.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Since Esri exposed the CIM model to ArcPy starting with Pro 2.4 (or was it 2.3), it opened the doors to doing a lot more within Pro that wasn't available strictly through ArcPy in the past with Pro.

danashney
New Contributor III

This seemed to work. It changed the def query without the duplication. Note that you have to change two CIM properties to get this to change without duplication AND to make the new query the 'active' query. 

# sorry for bad indents; I don't know how to format this here

# batch change (all maps in project) definition query for a specified layer
# optional param - specify which map you want to target, default is that it does all of them

def batch_change_definition_query(layer_name, definition_query, my_map = None):
aprx = arcpy.mp.ArcGISProject("CURRENT")
for map in aprx.listMaps(my_map):
for layer in map.listLayers():
if layer.name == layer_name:
cim_layer = layer.getDefinition('V2')
cim_layer.featureTable.definitionFilterChoices[0].definitionExpression = definition_query
cim_layer.featureTable.definitionExpression = definition_query
layer.setDefinition(cim_layer)

0 Kudos
MikeLachance1
New Contributor III

I was able to get this method to work as well. For context: I am running script tools  that allow users to set and clear definition queries for multiple layers. When setting, they select a value from a drop down list and run the script which creates and applies the query with their selected value to all the relevant layers. When clearing, they simply run the script tool and all definition queries are cleared from the relevant layers.

 

Here is an example of the syntax I used for clearing queries. I am into an issue where it gave an error if the layer didn't already have a DQ on it, so it couldn't overwrite it. So I check for existing DQs first, if there is one, I overwrite it, if there isn't one, I create and apply one.

aprx = arcpy.mp.ArcGISProject("CURRENT")
    m = aprx.activeMap
    lyrs = m.listLayers()
    
    for lyr in lyrs:
        if lyr.name in ('TEST_PT', 'TEST_LINE', 'TEST_POLY'):
            cim_layer = lyr.getDefinition('V2')
            
            if cim_layer.featureTable.definitionFilterChoices:
                cim_layer.featureTable.definitionFilterChoices[0].definitionExpression = None
                cim_layer.featureTable.definitionExpression = None
                
            else:
                cim_layer.featureTable.definitionExpression = None
            
            lyr.setDefinition(cim_layer)

Doing it this way allowed me to create, apply, and clear definition queries without creating a massive list of deactivated queries for each layer. Hope this helps others.

LindsayRaabe_FPCWA
Regular Contributor

For others looking for help in this space. 

I've just tested the below line in a python script that looks at a set map (Data Editing) in the Current project, and had the last 2 lines repeated for all the different layer names that I wanted it to update. It successfully deleted the definition query from each layer. 

aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Data Editing")[0]

for lyr in m.listLayers("Layer 1"):    ###Repeat these 2 lines for each layer
    lyr.definitionQuery = None

for lyr in m.listLayers("Layer 2"):    
    lyr.definitionQuery = None

I plan to write a simple script that can be used on any project and map which will just go through all layers in the current map and wipe and definition queries. Variations of this could include a 3rd line for each layer that adds a replacement query in the originals place. 

Lindsay Raabe
Forest Products Commission WA
0 Kudos
JimPuyda
New Contributor

Sorry,  lyr.definitionQuery = None    does not work.  It still is keeping all query clauses.   Frustrating.

0 Kudos