2013-05-13 43 views
1

我將在接下來的日子裏推出一款使用Django MPTT管理分層數據的應用程序。 MPTT提供了一個名爲rebuild的函數,該函數重建給定模型的所有可用樹,並且被稱爲TreeNodes.objects.rebuild()。正如你所看到的,該命令在模型上被調用,而不是在模型的一個實例上。這個命令必須在一個節點被插入樹中之後調用。Django MPTT - objects.rebuild有多貴?

對於Django MPTT 0.6(尚未官方released)執行partial_rebuild命令,該命令僅會重建給定的樹。

在本地測試最多10棵樹時,根本沒有性能問題,但是我擔心數據庫中有100棵樹,我打電話給rebuild命令(它將重建所有100個樹樹),這可能是一個重要的性能問題。

有沒有使用rebuild命令的經驗的人?

+1

任何原因,你會重建你的樹定期? – user2298943 2013-05-13 07:08:49

+1

據我瞭解,Django-mptt總是必須在向樹添加節點之後重新生成樹,如下所示:node.parent = parent,node.save(),它必須遵循TreeNodes.objects.rebuild()命令。 – 2013-05-13 07:27:21

+0

您是否測試了操作的結果,而無需任何後續重建?我敢說,這根本不是必要的。看看TreeManager的實現。 – 2013-05-13 16:27:52

回答

3

以供將來參考..

objects.rebuild()只需要在某些特殊情況下。通常情況下,只需設置節點的父節點id,就可以正確設置節點的左右值。這也是在docs

中提到我遇到了一個問題,沒有正確設置左,右值,因爲我保存了新的節點!我重置了其他已有的兄弟姐妹的位置值。爲具有元屬性order_insertion_by集的樹插入新節點時,必須首先重置所有兄弟的order_insertion_by值,然後保存新節點。這樣mptt能夠正確地重新計算左邊的值。

見我(簡化)下面的例子:

models.py

class Node(MPTTModel): 
    """ 
    Representation of a single node 
    """ 
    name = models.CharField(max_length=200) 
    parent = TreeForeignKey('self', null=True, blank=True, related_name='%(app_label)s_%(class)s_children') 
    position = models.PositiveIntegerField(max_length=10) #for nodes on the same hierarchy level we have to define the position in which they are displayed 

    class MPTTMeta: 
     order_insertion_by = ['position'] 

views.py

new_node = Node(name="new node", parent=parent_node, position=1) 
update_node_positions(new_node, 1) #routine to update the node positions 
new_node.save() 

update_node_positions

def update_node_positions(node, mode): 
    """ 
    Procedure to update the node positions 
    Three different modes available: 
     1 = insert node 
     2 = update position, parent stays the same 
     3 = update position and change parent 
     4 = trashed 
    """ 

    if mode == 1 or mode==3: 
     #if node has been inserted at the beginning 
     if node.position == 1: 
      node.get_siblings().update(position=F('position') + 1) 
     #if node has been inserted not at beginning and not at the last position 
     elif node.position != node.get_siblings().count() + 1: 
      #update positions of siblings right of node by one 
      node.get_siblings().filter(position__gte=node.position).update(position=F('position') + 1) 
     if mode == 3: 
      #since we removed the node from a parent, we have to decrement the positions of the former siblings right of the node by one 
      if node._original_parent is not None: 
       #do updates only for nodes which had a parent before. will not be executed for root nodes 
       node._original_parent.get_children().filter(position__gt=node._original_position).update(position=F('position') - 1) 
    if mode == 2: 
     #if old position is left of new position -> decrement position by 1 for nodes which have position <= node.position AND > node.original_position 
     if node.position > node._original_position: 
      node.get_siblings().filter(Q(position__lte=node.position) & Q(position__gt=node._original_position)).update(position=F('position') - 1) 
     #if old position is right of new position -> increment position by 1 for nodes which have position >= node.position AND < node.original_position 
     if node.position < node._original_position: 
      node.get_siblings().filter(Q(position__gte=node.position) & Q(position__lt=node._original_position)).update(position=F('position') + 1) 
    if mode == 4: 
     #decrement position by 1 for nodes which have position > node.position 
     node.get_siblings().filter(Q(position__gt=node.position)).update(position=F('position') - 1)