You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

85 lines
3.4 KiB

  1. # Tree (Hierarchical) Nested Set Model (nsm)
  2. #
  3. # To use the nested set model,
  4. # use the following pattern
  5. # 1. name your parent field as "parent_node" if not have a property nsm_parent_field as your field name in the document class
  6. # 2. have a field called "old_parent" in your fields list - this identifies whether the parent has been changed
  7. # 3. call update_nsm(doc_obj) in the on_upate method
  8. # ------------------------------------------
  9. import webnotes
  10. # called in the on_update method
  11. def update_nsm(doc_obj):
  12. # get fields, data from the DocType
  13. d = doc_obj.doc
  14. pf, opf = 'parent_node', 'old_parent'
  15. if hasattr(doc_obj,'nsm_parent_field'):
  16. pf = doc_obj.nsm_parent_field
  17. if hasattr(doc_obj,'nsm_oldparent_field'):
  18. opf = doc_obj.nsm_oldparent_field
  19. p, op = d.fields[pf], d.fields.get(opf, '')
  20. # has parent changed (?) or parent is None (root)
  21. if not doc_obj.doc.lft and not doc_obj.doc.rgt:
  22. update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf)
  23. elif op != p:
  24. update_remove_node(doc_obj.doc.doctype, doc_obj.doc.name)
  25. update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf)
  26. # set old parent
  27. webnotes.conn.set(d, opf, p or '')
  28. def rebuild_tree(doctype, parent_field):
  29. # get all roots
  30. right = 1
  31. result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='' or `%s` IS NULL" % (doctype, parent_field, parent_field))
  32. for r in result:
  33. right = rebuild_node(doctype, r[0], right, parent_field)
  34. def rebuild_node(doctype, parent, left, parent_field):
  35. # the right value of this node is the left value + 1
  36. right = left+1
  37. # get all children of this node
  38. result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='%s'" % (doctype, parent_field, parent))
  39. for r in result:
  40. right = rebuild_node(doctype, r[0], right, parent_field)
  41. # we've got the left value, and now that we've processed
  42. # the children of this node we also know the right value
  43. webnotes.conn.sql('UPDATE `tab%s` SET lft=%s, rgt=%s WHERE name="%s"' % (doctype,left,right,parent))
  44. #return the right value of this node + 1
  45. return right+1
  46. def update_add_node(doctype, name, parent, parent_field):
  47. # get the last sibling of the parent
  48. if parent:
  49. right = webnotes.conn.sql("select rgt from `tab%s` where name='%s'" % (doctype, parent))[0][0]
  50. else: # root
  51. right = webnotes.conn.sql("select ifnull(max(rgt),0)+1 from `tab%s` where ifnull(`%s`,'') =''" % (doctype, parent_field))[0][0]
  52. right = right or 1
  53. # update all on the right
  54. webnotes.conn.sql("update `tab%s` set rgt = rgt+2 where rgt >= %s" %(doctype,right))
  55. webnotes.conn.sql("update `tab%s` set lft = lft+2 where lft >= %s" %(doctype,right))
  56. # update index of new node
  57. if webnotes.conn.sql("select * from `tab%s` where lft=%s or rgt=%s"% (doctype, right, right+1)):
  58. webnotes.msgprint("Nested set error. Please send mail to support")
  59. raise Exception
  60. webnotes.conn.sql("update `tab%s` set lft=%s, rgt=%s where name='%s'" % (doctype,right,right+1,name))
  61. return right
  62. def update_remove_node(doctype, name):
  63. left = webnotes.conn.sql("select lft from `tab%s` where name='%s'" % (doctype,name))
  64. if left[0][0]:
  65. # reset this node
  66. webnotes.conn.sql("update `tab%s` set lft=0, rgt=0 where name='%s'" % (doctype,name))
  67. # update all on the right
  68. webnotes.conn.sql("update `tab%s` set rgt = rgt-2 where rgt > %s" %(doctype,left[0][0]))
  69. webnotes.conn.sql("update `tab%s` set lft = lft-2 where lft > %s" %(doctype,left[0][0]))