ArcGIS Pro - Modifying Layer Definition query via ArcPY

9528
12
10-08-2019 07:36 PM
janrykr1
Emerging Contributor

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
12 Replies
FPCWAGIS_Admin
Occasional Contributor

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
Emerging Contributor

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
Regular Contributor

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
Regular Contributor

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.

Joseph_Kinyon
Frequent Contributor

Mike,

Would love to see the whole script tool you created if you have a moment.
What you have created is very close to my tool.

Select Layers>choose or write query definition (or set to clear)>check if definition query exists > update definition query

0 Kudos
MikeLachance1
Regular Contributor

Hi Joseph, sorry for the late reply. What is posted is the entirety of the code within my "Clear All Filters" GP script tool that my users run. Were you interested in seeing the script for setting definition queries as well?

0 Kudos
CarsonGEO
Emerging Contributor

Hi Mike, I would be very interested in seeing how to set the definition queries.

0 Kudos