Search code examples
pythondjangolistmpttdescendant

django-mptt get_descendants for a list of nodes


I am trying to get all descendants(include_self=True) not for one Node, but for a list (a QuerySet) of Nodes. This should be one SQL query.

Example (that actually is not working:)

some_nodes = Node.objects.filter( ...some_condition... ) 
some_nodes.get_descendants(include_self=True) #hopefully I would like 
to have all possible Nodes starting from every node of "some_nodes" 

The only idea I have right now is to iterate through some_nodes and run get_descendants() for every node - but this is terrible solution (plenty of SQL queries).

If there is no clean way to do it via Django ORM can you provide me a custom SQL to run instead? Here you can make assumption that I have a list of Node's pk.

EDIT: If that could help - all of my "some_nodes" are placed in the same parent directory and have the same "level" in the tree.


Solution

  • Great thanks to Craig de Stigter answered my question on django-mptt-dev group, in case anybody need it I am kindly reposting his solution from http://groups.google.com/group/django-mptt-dev/browse_thread/thread/637c8b2fe816304d

       from django.db.models import Q 
       import operator 
       def get_queryset_descendants(nodes, include_self=False): 
           if not nodes: 
               return Node.tree.none() 
           filters = [] 
           for n in nodes: 
               lft, rght = n.lft, n.rght 
               if include_self: 
                   lft -=1 
                   rght += 1 
               filters.append(Q(tree_id=n.tree_id, lft__gt=lft, rght__lt=rght)) 
           q = reduce(operator.or_, filters) 
           return Node.tree.filter(q) 
    

    Example Node tree:

    T1 
    ---T1.1 
    ---T1.2 
    T2 
    T3 
    ---T3.3 
    ------T3.3.3 
    

    Example usage:

       >> some_nodes = [<Node: T1>, <Node: T2>, <Node: T3>]  # QureySet
       >> print get_queryset_descendants(some_nodes)
       [<Node: T1.1>, <Node: T1.2>, <Node: T3.3>, <Node: T3.3.3>] 
       >> print get_queryset_descendants(some_nodes, include_self=True)
       [<Node: T1>, <Node: T1.1>, <Node: T1.2>, <Node: T2>, <Node: T3>, <Node: T3.3>, <Node: T3.3.3>]