Fix union, intersection, and difference operations with tree fields
Fixes an issue where using union, intersection, or difference operations on querysets with tree fields would raise errors. The problem manifested in two ways:
-
Missing parameter error:
TreeQuery.get_compiler() takes from 1 to 3 positional arguments but 4 were given -
Field resolution error:
Cannot resolve keyword 'tree_depth' into field
Root Cause
Tree fields like tree_depth, tree_path, and tree_ordering are computed fields generated via Common Table Expressions (CTEs) and are not actual database columns. Django's combinator SQL generation for union/intersection/difference operations requires all queries to have matching field structures, but tree fields cannot be resolved as regular model fields.
Solution
The fix implements automatic detection of combinator operations and falls back to regular SQL compilation without tree fields:
-
Fixed method signature: Updated
TreeQuery.get_compiler()to accept theelide_emptyparameter that Django's combinator logic passes -
Smart fallback: When a
TreeQueryis part of a combinator operation, it automatically compiles as a regular query without CTE generation - Clean SQL: Ensures all queries in combinator operations use compatible field structures
Usage
from tree_queries.models import TreeNode
class Category(TreeNode):
name = models.CharField(max_length=100)
# These now work without errors:
Category.objects.with_tree_fields().union(Category.objects.with_tree_fields())
Category.objects.with_tree_fields().intersection(Category.objects.with_tree_fields())
Category.objects.with_tree_fields().difference(Category.objects.with_tree_fields())
Behavior
-
Regular tree queries: Continue to work normally with full tree fields (
tree_depth,tree_path, etc.) - OR operations: Continue to work normally with tree fields
- Union/Intersection/Difference: Now work correctly but without tree fields (documented limitation)
This is a backward-compatible change that adds new functionality without breaking existing code.
Fixes #55.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.