2010-06-14 19 views
5

django-mptt parece decidido a sacarme de la cabeza. Estoy tratando de hacer algo relativamente simple: voy a eliminar un nodo, y necesito hacer algo razonable con los hijos del nodo. A saber, me gustaría moverlos a un nivel para que sean hijos de los padres de sus padres actuales.django-mptt: cómo mover nodos con éxito alrededor de

Es decir, si el árbol se parece a:

Root 
    | 
Grandpa 
    | 
Father 
| | 
C1 C2 

Voy a eliminar Padre, y me gustaría C1 y C2 a ser hijos de abuelo.

Aquí está el código que estoy usando:

class Node(models.Model): 
    first_name = models.CharField(max_length=80, blank=True) 
    parent  = models.ForeignKey('self', null=True, blank=True, related_name='children') 

    def reparent_children(self, parent): 
     print "Reparenting" 
     for child in self.get_children(): 
      print "Working on", child.first_name, "to parent", parent.email 
      parent = Node.objects.get(id=parent.id) 
      child.move_to(parent, 'last-child') 
      child.save() 

Así que yo llamaría:

father.reparent_children(grandpa) 
father.parent = None 
father.save() 

Esto funciona - casi. Los niños informan a sus padres como abuelo:

c1.parent == grandpa # True 

abuelo recuentos C1 y C2 entre sus hijos

c1 in grandpa.children.all() # True 

Sin embargo, Raíz reniega de estos niños.

c1.get_root() == father # c1's root is father, instead of Root 

c1 in root.get_descendants() # False 

¿Cómo hago que los niños se muevan y que no se corrompa su raíz?

+1

¿está seguro de que "father.parent = None" es la forma correcta para borrar un nodo? – mawimawi

+0

En este caso, en realidad no estoy borrando el nodo, lo estoy archivando. Me gustaría eliminarlo del árbol. Aunque tiene un buen punto, en realidad no lo estoy quitando del árbol aquí. – Parand

+0

Parece que establecer el padre en Ninguno y guardar es en realidad la forma de eliminar un nodo de un árbol (de acuerdo con los casos de prueba mptt), para que se vea bien. – Parand

Respuesta

6

Los valores internos lft y rght cambiarán la primera vez que guarde un elemento secundario (es decir, la última línea de su método reparent_children). save() no actualiza las instancias que pueda tener por ahí. Yo creo una manera segura de hacer esto sería refetch desde la base de datos cada vez, así:

def reparent_children(self, parent): 
    print "Reparenting" 
    for child in self.get_children(): 
     print "Working on", child.first_name, "to parent", parent.email 
     parent = Node.objects.get(id=parent.id) 
     current_child = Node.objects.get(id = child.id) 
     current_child.move_to(parent, 'last-child') 
     current_child.save() 

tuve similar problems un tiempo atrás, y que el enfoque resuelto mi problema.

+4

Dominic, terminé con este método, y * seem * funciona, aunque con django-mptt I end constantemente cuestionando mi propia cordura.No sé si realmente solucioné el problema o lo escondí en otro lado. – Parand

1

Esta biblioteca realmente me ha confundido estos últimos días - move_to realmente no parece hacer lo que quiero, y mi árbol no se sincroniza. Se me ocurrió una solución en la que confío más, a expensas de la velocidad y la no tradición.

Gira en torno al método de administrador partial_rebuildhere.

def delete_node(self): 
    if not self.parent: 
     print("Should not delete root node, confusing behavior follows") 
     return 
    tree_id = self.tree_id 
    parent = self.parent 

    for child in self.get_children(): 
     child.parent = parent 
     child.save() 

    self.delete() 
    Node.objects.partial_rebuild(tree_id) 

Puede reemplazar child.parent = padre con child.move_node (padre) si desea

Cuestiones relacionadas