Hello, I am trying to create a definition query for layers in a specific group. The following works to create the definition query in the group but I was wondering if there is a way to name the query rather than it defaulting to Query 1.
aprx = arcpy.mp.ArcGISProject("CURRENT")
# Access the map
map_obj = aprx.listMaps("Map")[0]
# Define the definition query
definition_query = "field = 'value'"
# Apply the definition query to all layers in a specific group
group_layer_name = "Working"
group_layer = map_obj.listLayers(group_layer_name)[0]
for layer in group_layer.listLayers():
if layer.isFeatureLayer:
layer.definitionQuery = definition_query
Thanks!
Yes, I did. I thought it was doing nothing when running it in a notebook but now I need to look back at it, because I tried it again and it is only applying it to the first layer in the TOC.
Here's a set of functions I use to manage my layer queries:
from pprint import pformat
from arcpy.mp import ArcGISProject
from arcpy._mp import Map, Layer
from typing import Any
def get_project_queries(project: ArcGISProject) -> dict[str: Any]:
"""Gets the queries from a project
@param project: The project to get the queries from
@return: The dictionary of queries
"""
out_dict = {}
for mp in project.listMaps():
mp: Map = mp
out_dict[mp.name] = {}
for lyr in mp.listLayers():
lyr: Layer = lyr
if lyr.supports("definitionQuery") and lyr.definitionQuery:
out_dict[mp.name][lyr.longName] = lyr.listDefinitionQueries()
return {k : v for k, v in out_dict.items() if v}
def _merge_definition_queries(queries: dict[str, Any], mp: Map, lyr: Layer) -> list[dict[str, Any]]:
"""Merges multiple enabled queries into one
Useful for writing out multiple queries into a config file and then merging them into a single query
@param queries: The queries dictionary
@param mp: The map
@param lyr: The layer
@return: The merged queries
"""
updates = []
# Get enabled queries
enabled_queries = \
[
(q['name'], q['sql'])
for q in queries[mp.name][lyr.longName]
if q['isActive']
]
# Merge name and query if there are multiple enabled queries for a layer
merged_name = "/".join([name for name, _ in enabled_queries])
merged_sql = " AND ".join([sql for _, sql in enabled_queries])
# Save Updates
updates.append({"name": merged_name, "sql": merged_sql, "isActive": True})
if updates:
# Apply merged queries
updates.extend([q for q in queries[mp.name][lyr.longName] if not q['isActive']])
queries[mp.name][lyr.longName] = updates
return queries
def set_project_queries(project: ArcGISProject, queries: dict[str: Any]) -> None:
"""Sets the queries from a project
@param project: The project to set the queries on
@param queries: The queries to set
"""
# Iterate Maps
for mp in project.listMaps():
mp: Map = mp
if mp.name not in queries:
continue
# Iterate Map Layers
for lyr in mp.listLayers():
lyr: Layer = lyr
# Skip if the layer is not in the queries dictionary
if lyr.longName not in queries[mp.name]:
continue
# Handle the case where multiple queries are enabled
if len(queries[mp.name][lyr.longName]) > 1:
queries = _merge_definition_queries(queries, mp, lyr)
lyr.updateDefinitionQueries(queries[mp.name][lyr.longName])
return
The general idea is to take the output of get_project_queries and write it into a config file somewhere so you can then use the other two functions to load that config back in (json.dumps and json.loads). I kept the pformat import up there so you can use that to format your dump so it's easier to read and edit.
Hi @CarsonGEO
You can indeed. You can use a dictionary and update the list of definition queries for each layer.
definition_query = {"name" : "NAME_IT_HERE", "sql" : "field = 'value'", "isActive" : True}
for layer in group_layer.listLayers():
## Get teh current list of DQs (it could be empty)
definition_query_list = lyr.listDefinitionQueries()
## Append in the new DQ
definition_query_list.append(definition_query)
## Update the DQs for the layer
layer.updateDefinitionQueries(definition_query_list)
Now, only one Definition Query per layer can be Active. If you have multiple per layer you can iterate over these from the list returned by listDefinitionQueries and set the isActive to False for these and then append in the new DQ (as above) and set as Active.
All the best,
Glen