2013-05-13 5 views
1

장고 MPTT를 사용하여 계층 적 데이터를 관리하는 응용 프로그램을 다음 날에 출시 할 예정입니다. MPTT는 rebuild이라는 함수를 제공합니다.이 함수는 주어진 모델에 사용할 수있는 모든 트리를 다시 작성하며 TreeNodes.objects.rebuild()이라고합니다. 보시다시피 명령은 모델 인스턴스에서가 아니라 모델에서 호출됩니다. 이 명령은 노드가 트리에 삽입 된 후에 호출되어야합니다.Django MPTT - objects.rebuild는 얼마나 비쌉니까?

Django MPTT 0.6 (아직 공식적으로 released이 아님)의 경우 partial_rebuild 명령이 구현되어 지정된 트리를 다시 작성합니다.

최대 10 개의 트리를 사용하여 로컬에서 테스트하는 동안 성능에 전혀 문제가 없지만 db에 100 개의 트리가있는 경우 염려 스럽습니다. rebuild 명령을 호출합니다 (100 개 모두를 다시 작성 함). 나무), 이것은 중요한 성능 문제가 될 수 있습니다.

누구도 rebuild 명령을 사용한 경험이 있습니까?

+1

당신이 당신의 나무를 다시 할 모든 이유 정기적으로? – user2298943

+1

Django-mptt를 이해하는 한, 트리에 노드를 추가 한 후 항상 트리를 다시 빌드해야합니다. node.parent = parent, node.save(). TreeNodes.objects.rebuild()를 따라야합니다. 명령. –

+0

이후 작업을 다시 수행하지 않고 작업 결과를 테스트 했습니까? 나는 이것이 전혀 필요하지 않다는 것을 감히 말한다. TreeManager 구현을 살펴보십시오. –

답변

3

나중에 참조 할 수 있도록 ...

objects.rebuild()는 특별한 경우에만 필요합니다. 일반적으로 mptt는 노드의 부모 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)