def process(self): # do we have a root node already? last_root = self.cls.get_last_root_node() if last_root and last_root.node_order_by: # there are root nodes and node_order_by has been set # delegate sorted insertion to add_sibling return last_root.add_sibling('sorted-sibling', **self.kwargs) if last_root: # adding the new root node as the last one newpath = last_root._inc_path() else: # adding the first root node newpath = self.cls._get_path(None, 1, 1) if len(self.kwargs) == 1 and 'instance' in self.kwargs: # adding the passed (unsaved) instance to the tree newobj = self.kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating the new object newobj = self.cls(**self.kwargs) newobj.depth = 1 newobj.path = newpath # saving the instance before returning it newobj.save() return newobj
def add_child(self, **kwargs): """Adds a child to the node.""" cls = get_result_class(self.__class__) if len(kwargs) == 1 and 'instance' in kwargs: # adding the passed (unsaved) instance to the tree newobj = kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: newobj = cls(**kwargs) try: newobj._cached_depth = self._cached_depth + 1 except AttributeError: pass if not cls.node_order_by: try: max = cls.objects.filter(parent=self).reverse()[0].sib_order except IndexError: max = 0 newobj.sib_order = max + 1 newobj.parent = self newobj.save() return newobj
def add_root(cls, **kwargs): """Adds a root node to the tree.""" # do we have a root node already? last_root = cls.get_last_root_node() if last_root and last_root.node_order_by: # there are root nodes and node_order_by has been set # delegate sorted insertion to add_sibling return last_root.add_sibling('sorted-sibling', **kwargs) if last_root: # adding the new root node as the last one newtree_id = last_root.tree_id + 1 else: # adding the first root node newtree_id = 1 if len(kwargs) == 1 and 'instance' in kwargs: # adding the passed (unsaved) instance to the tree newobj = kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating the new object newobj = get_result_class(cls)(**kwargs) newobj.depth = 1 newobj.tree_id = newtree_id newobj.lft = 1 newobj.rgt = 2 # saving the instance before returning it newobj.save() return newobj
def process(self): if self.node.object_id != self.kwargs.get('object_id', False): raise KeyError( "The object_id for parent and child must be the same") if self.node_cls.node_order_by and not self.node.is_leaf(): # there are child nodes and node_order_by has been set # delegate sorted insertion to add_sibling self.node.numchild += 1 return self.node.get_last_child().add_sibling( 'sorted-sibling', **self.kwargs) if len(self.kwargs) == 1 and 'instance' in self.kwargs: # adding the passed (unsaved) instance to the tree newobj = self.kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating a new object newobj = self.node_cls(**self.kwargs) newobj.depth = self.node.depth + 1 if self.node.is_leaf(): # the node had no children, adding the first child newobj.path = self.node_cls._get_path(self.node.path, newobj.depth, 1) # now we use Text instead varchar and this is extra check # max_length = self.node_cls._meta.get_field('path').max_length # if len(newobj.path) > max_length: # raise PathOverflow( # _('The new node is too deep in the tree, try' # ' increasing the path.max_length property' # ' and UPDATE your database')) else: # adding the new child as the last one newobj.path = self.node.get_last_child()._inc_path() # saving the instance before returning it newobj.save() newobj._cached_parent_obj = self.node get_result_class(self.node_cls).objects.filter( path=self.node.path, object_id=self.node.object_id).update(numchild=F('numchild') + 1) # we increase the numchild value of the object in memory self.node.numchild += 1 return newobj
def add_child(self, **kwargs): """Adds a child to the node.""" if not self.is_leaf(): # there are child nodes, delegate insertion to add_sibling if self.node_order_by: pos = 'sorted-sibling' else: pos = 'last-sibling' last_child = self.get_last_child() last_child._cached_parent_obj = self return last_child.add_sibling(pos, **kwargs) # we're adding the first child of this node sql, params = self.__class__._move_right(self.tree_id, self.rgt, False, 2) if len(kwargs) == 1 and 'instance' in kwargs: # adding the passed (unsaved) instance to the tree newobj = kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating a new object newobj = get_result_class(self.__class__)(**kwargs) newobj.tree_id = self.tree_id newobj.depth = self.depth + 1 newobj.lft = self.lft + 1 newobj.rgt = self.lft + 2 # this is just to update the cache self.rgt += 2 newobj._cached_parent_obj = self cursor = self._get_database_cursor('write') cursor.execute(sql, params) # saving the instance before returning it newobj.save() transaction.commit_unless_managed() return newobj
def add_sibling(self, pos=None, **kwargs): """Adds a new node as a sibling to the current node object.""" pos = self._prepare_pos_var_for_add_sibling(pos) if len(kwargs) == 1 and 'instance' in kwargs: # adding the passed (unsaved) instance to the tree newobj = kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating a new object newobj = get_result_class(self.__class__)(**kwargs) if not self.node_order_by: newobj.sib_order = self.__class__._get_new_sibling_order(pos, self) newobj.parent_id = self.parent_id newobj.save() return newobj
def process(self): self.pos = self.node._prepare_pos_var_for_add_sibling(self.pos) if len(self.kwargs) == 1 and 'instance' in self.kwargs: # adding the passed (unsaved) instance to the tree newobj = self.kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating a new object newobj = self.node_cls(**self.kwargs) newobj.depth = self.node.depth if self.pos == 'sorted-sibling': siblings = self.node.get_sorted_pos_queryset( self.node.get_siblings(), newobj) try: newpos = siblings.all()[0]._get_lastpos_in_path() except IndexError: newpos = None if newpos is None: self.pos = 'last-sibling' else: newpos, siblings = None, [] _, newpath = self.reorder_nodes_before_add_or_move( self.pos, newpos, self.node.depth, self.node, siblings, None, False) parentpath = self.node._get_basepath(newpath, self.node.depth - 1) if parentpath: self.stmts.append( self.get_sql_update_numchild(parentpath, 'inc')) self.run_sql_stmts() # saving the instance before returning it newobj.path = newpath newobj.save() return newobj
def add_root(cls, **kwargs): """Adds a root node to the tree.""" if len(kwargs) == 1 and 'instance' in kwargs: # adding the passed (unsaved) instance to the tree newobj = kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: newobj = cls(**kwargs) newobj._cached_depth = 1 if not cls.node_order_by: try: max = get_result_class(cls).objects.filter( parent__isnull=True).order_by( 'sib_order').reverse()[0].sib_order except IndexError: max = 0 newobj.sib_order = max + 1 newobj.save() return newobj
def add_sibling(self, pos=None, **kwargs): """Adds a new node as a sibling to the current node object.""" pos = self._prepare_pos_var_for_add_sibling(pos) if len(kwargs) == 1 and 'instance' in kwargs: # adding the passed (unsaved) instance to the tree newobj = kwargs['instance'] if newobj.pk: raise NodeAlreadySaved("Attempted to add a tree node that is "\ "already in the database") else: # creating a new object newobj = get_result_class(self.__class__)(**kwargs) newobj.depth = self.depth sql = None target = self if target.is_root(): newobj.lft = 1 newobj.rgt = 2 if pos == 'sorted-sibling': siblings = list( target.get_sorted_pos_queryset(target.get_siblings(), newobj)) if siblings: pos = 'left' target = siblings[0] else: pos = 'last-sibling' last_root = target.__class__.get_last_root_node() if ((pos == 'last-sibling') or (pos == 'right' and target == last_root)): newobj.tree_id = last_root.tree_id + 1 else: newpos = { 'first-sibling': 1, 'left': target.tree_id, 'right': target.tree_id + 1 }[pos] sql, params = target.__class__._move_tree_right(newpos) newobj.tree_id = newpos else: newobj.tree_id = target.tree_id if pos == 'sorted-sibling': siblings = list( target.get_sorted_pos_queryset(target.get_siblings(), newobj)) if siblings: pos = 'left' target = siblings[0] else: pos = 'last-sibling' if pos in ('left', 'right', 'first-sibling'): siblings = list(target.get_siblings()) if pos == 'right': if target == siblings[-1]: pos = 'last-sibling' else: pos = 'left' found = False for node in siblings: if found: target = node break elif node == target: found = True if pos == 'left': if target == siblings[0]: pos = 'first-sibling' if pos == 'first-sibling': target = siblings[0] move_right = self.__class__._move_right if pos == 'last-sibling': newpos = target.get_parent().rgt sql, params = move_right(target.tree_id, newpos, False, 2) elif pos == 'first-sibling': newpos = target.lft sql, params = move_right(target.tree_id, newpos - 1, False, 2) elif pos == 'left': newpos = target.lft sql, params = move_right(target.tree_id, newpos, True, 2) newobj.lft = newpos newobj.rgt = newpos + 1 # saving the instance before returning it if sql: cursor = self._get_database_cursor('write') cursor.execute(sql, params) newobj.save() return newobj