2010-06-14 15 views
5

Il django-mptt sembra determinato a farmi uscire di testa. Sto cercando di fare qualcosa di relativamente semplice: eliminerò un nodo e devo fare qualcosa di ragionevole con i figli del nodo. Vale a dire, mi piacerebbe spostarli di un livello in modo che siano figli del genitore del loro attuale genitore.django-mptt: come spostare con successo i nodi intorno a

Cioè, se l'albero si presenta come:

Root 
    | 
Grandpa 
    | 
Father 
| | 
C1 C2 

ho intenzione di eliminare Padre, e vorrei C1 e C2 di essere figli di nonno.

Ecco il codice che sto utilizzando:

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() 

Quindi io chiamerei:

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

Questo funziona - quasi. I bambini riportano i loro genitori come il nonno:

c1.parent == grandpa # True 

nonno conta C1 e C2 tra i suoi figli

c1 in grandpa.children.all() # True 

Tuttavia, Radice rinnega questi ragazzi.

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

c1 in root.get_descendants() # False 

Come faccio a spostare i bambini e la loro radice non viene danneggiata?

+1

sei sicuro che "father.parent = None" è il modo giusto per eliminare un nodo? – mawimawi

+0

In questo caso, in realtà non sto eliminando il nodo: lo sto archiviando. Mi piacerebbe rimuoverlo dall'albero. Hai comunque un buon punto, non lo sto effettivamente rimuovendo dall'albero qui. – Parand

+0

Sembra impostare il genitore su Nessuno e il salvataggio è in realtà il modo per rimuovere un nodo da un albero (in base ai test del test di mptt), in modo che sia corretto. – Parand

risposta

6

I valori interni lft e rght cambieranno la prima volta che si salva un figlio (ad esempio la linea finale del metodo reparent_children). save() non aggiorna le istanze che potresti aver mentito. I pensare un modo sicuro per fare questo sarebbe per loro recupera nuovamente dal database ogni volta, in questo modo:

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() 

ho avuto similar problems un po 'indietro, e che l'approccio risolto il mio problema.

+4

Dominic, ho finito con questo metodo, e * sembra * funzionare, anche se con django-mptt I end costantemente interrogando la mia sanità mentale.Non so se ho effettivamente risolto il problema o nascosto altrove da qualche altra parte. – Parand

1

Questa libreria mi ha davvero confuso in questi ultimi giorni - move_to non sembra davvero fare ciò che voglio e il mio albero continua a non essere sincronizzato. Ho trovato una soluzione in cui sono più fiducioso, a scapito della velocità e della non-tradizione.

Riguarda il metodo gestore 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) 

È possibile sostituire child.parent = genitore con child.move_node (genitore) se vuoi