Debugging DAG Queries¶
django-postgresql-dag builds recursive CTEs for graph traversal, and by default the generated SQL is invisible. The log_queries context manager lets you inspect the CTE SQL on demand, with zero overhead when not in use.
Basic usage¶
from django_postgresql_dag.debug import log_queries
with log_queries() as log:
descendants = node.descendants()
path = node.path(other_node)
for q in log.queries:
print(q["query_class"]) # e.g. "DescendantQuery", "DownwardPathQuery"
print(q["sql"]) # Full CTE SQL
print(q["params"]) # Parameter dict
Quick shell debugging¶
Pass print_queries=True to print all captured queries when the context exits:
with log_queries(print_queries=True):
node.descendants()
Capturing executed queries¶
To capture the actual queries executed by Django (with timing data), use capture_executed=True. This wraps Django’s CaptureQueriesContext internally:
with log_queries(capture_executed=True) as log:
node.descendants()
for e in log.executed:
print(f"{e['time']}s: {e['sql'][:100]}")
Decorator form¶
log_queries also works as a decorator:
@log_queries(print_queries=True)
def debug_my_operation():
node.descendants()
node.ancestors()
What gets captured¶
These operations are captured when called inside a log_queries block:
ancestors()/ancestors_raw()- recordsAncestorQuerydescendants()/descendants_raw()- recordsDescendantQueryancestors_with_depth()- recordsAncestorDepthQuerydescendants_with_depth()- recordsDescendantDepthQuerypath()/path_raw()- recordsDownwardPathQueryand/orUpwardPathQueryall_paths()/all_paths_as_pk_lists()- recordsAllDownwardPathsQueryand/orAllUpwardPathsQueryweighted_path()/weighted_path_raw()- recordsWeightedDownwardPathQueryand/orWeightedUpwardPathQueryconnected_graph()/connected_graph_raw()- recordsConnectedGraphQuerylowest_common_ancestors()- recordsLCAQuerytopological_sort()- recordsTopologicalSortQuerycritical_path()- recordsCriticalPathQuerytransitive_reduction()- recordsTransitiveReductionQuerynode_depth()- recordsnode_depth
DAGQueryLog reference¶
The object returned by log_queries().__enter__() is a DAGQueryLog instance with:
queries(list[dict]) - each entry has:query_class(str): the query builder class name (e.g."DescendantQuery") or"node_depth"sql(str): the formatted CTE SQL templateparams(dict): the parameters passed to the query
executed(list[dict]) - only populated whencapture_executed=True. Each entry has:sql(str): the actual SQL executed by Djangotime(str): execution time in seconds