Skip to content

Commit a20eabc

Browse files
matthiaskclaude
andcommitted
Refs #75: Document limitations with complex aggregations and subqueries
Added documentation explaining that the top-down CTE construction makes certain operations difficult or impossible: - Bottom-up aggregations (e.g., sum of all descendants) - Using tree fields in complex subqueries with OuterRef Provided workarounds: - Python-based computation for small trees - Pointer to django-cte for more complex CTE requirements - Suggestion to evaluate alternative tree storage approaches Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 3bb0f74 commit a20eabc

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Next version
2828
- Added documentation for limiting tree depth using ``.extra()`` and limiting
2929
children per node using model validation, with examples for checking depth
3030
programmatically.
31+
- Added documentation about limitations with complex aggregations and subqueries
32+
due to top-down CTE construction, with pointers to django-cte for more complex
33+
requirements.
3134

3235
0.23 (2025-11-27)
3336
~~~~~~~~~~~~~~~~~

README.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,43 @@ If you need to validate or check depth without tree fields:
532532
current = current.parent
533533
return depth
534534
535+
Complex aggregations and subqueries
536+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
537+
538+
The recursive CTE used by django-tree-queries builds the tree top-down from root
539+
nodes to descendants. This makes certain operations, like aggregating values
540+
bottom-up (from descendants to ancestors) or using tree fields in complex
541+
subqueries, difficult or impossible.
542+
543+
.. code-block:: python
544+
545+
# This doesn't work - can't use tree fields in subqueries with OuterRef
546+
Branch.objects.annotate(
547+
descendant_sum=Subquery(
548+
Branch.objects.descendants(of=OuterRef('pk')).aggregate(Sum('amount'))
549+
)
550+
)
551+
552+
**Workaround for small trees:** Load the tree into memory and compute in Python:
553+
554+
.. code-block:: python
555+
556+
# For small trees, load root nodes and calculate in Python
557+
roots = Branch.objects.filter(parent=None)
558+
for root in roots:
559+
descendants = root.descendants(include_self=True)
560+
total = sum(node.amount for node in descendants)
561+
# Use the total...
562+
563+
**For complex query requirements:** If you need extensive CTE customization,
564+
subqueries with tree fields, or bottom-up aggregations, consider using
565+
`django-cte <https://github.com/dimagi/django-cte>`_ which provides more control
566+
over recursive CTE construction, or evaluate whether a different tree storage
567+
approach (like django-treebeard with nested sets) better fits your needs.
568+
569+
For discussion of this limitation, see `GitHub issue #75
570+
<https://github.com/matthiask/django-tree-queries/issues/75>`_.
571+
535572

536573
Breadth-first search
537574
--------------------

0 commit comments

Comments
 (0)