2011-04-19 19 views
12

Estoy tratando de obtener todos descendants(include_self=True) no para uno Nodo, pero para una lista (un QuerySet) de Nodos. Esta debe ser una consulta de SQL .django-mptt get_descendants para obtener una lista de nodos

Ejemplo (:) que

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" 

La única idea en realidad no está funcionando tengo en este momento es para recorrer some_nodes y get_descendants run() para cada nodo - pero esto es terrible solución (un montón de consultas SQL).

Si no hay una manera clara de hacerlo a través de Django ORM, ¿me puede dar un SQL personalizado para ejecutar en su lugar? Aquí puede suponer que tengo una lista de Node's pk.

EDITAR: Si eso pudiera ayudar, todos mis "algunos_nodos" se colocan en el mismo directorio principal y tienen el mismo "nivel" en el árbol.

Respuesta

9

Muchas gracias a Craig de Stigter respuestas en grupo Django-MPTT-dev, por si alguien lo necesita estoy amablemente reposting su solución de http://groups.google.com/group/django-mptt-dev/browse_thread/thread/637c8b2fe816304d árbol

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) 

Ejemplo Nodo:

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

Ejemplo de uso:

>> 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>] 
+0

¡Esto es genial! Creo que debería 'Node.objects' en lugar de' Node.tree' aunque – Cory

+0

En realidad, esto ahora está integrado en el administrador. Ver mi respuesta alternativa. – Cory

1

Django mptt utiliza el método de recorrido modificado del árbol de pre orden como se describe en el documento MySQL Managing Hierarchical Data.

Se tiene la siguiente consulta para el retorno de todos los nodos en un árbol por debajo de un cierto nodo:

SELECT node.name 
FROM nested_category AS node, nested_category AS parent 
WHERE node.lft BETWEEN parent.lft AND parent.rgt 
    AND parent.name = 'ELECTRONICS' 
ORDER BY node.lft; 

El secreto está en los números parent.lft y parent.rgt, todos los niños tendrán un valor node.lft entre los dos.

Obviamente, este ejemplo presupone solo un padre y que debe usar el nombre principal para buscar el padre. Y cuando tenga los datos del nodo padre ya que puede hacer algo como lo siguiente:

SELECT node.id 
FROM node_table 
WHERE node.lft BETWEEN parent[0].lft AND parent[0].rgt 
    OR node.lft BETWEEN parent[1].lft AND parent[1].rgt 

Lo dejo como ejercicio para usted en cuanto a la manera de generar una cláusula independiente ENTRE para cada nodo padre (pista " Y "unir")

Alternativamente, puede usar un generador de rango en cada elemento primario para obtener todos los valores entre los valores de lft y rgt de cada padre inclusive. Eso le permite usar una declaración IN gigante en lugar de muchas cláusulas BETWEEN.

Combina cualquiera de los anteriores con un RawQueryset y recuperarás los modelos.

+0

Hmm, me he dado cuenta de que podría utilizar este mismo por el problema relacionado con la extracción de los padres por un gran número de árboles que también es enormemente lento debido a una gran cantidad de llamadas de consulta generadas – Chris

+0

Esta no es una respuesta muy precisa a lo que pregunté: ¡no tree_id en esta declaración! Por lo tanto, la idea es correcta para seleccionar nodos entre lft y right. – thedk

Cuestiones relacionadas