2
>>> from datetime import date
3
>>> from mptt.exceptions import InvalidMove
4
>>> from mptt.tests.models import Category, Genre, Insert, MultiOrder, Node, OrderedInsertion, Tree
6
>>> def print_tree_details(nodes):
7
... opts = nodes[0]._meta
8
... print '\n'.join(['%s %s %s %s %s %s' % \
9
... (n.pk, getattr(n, '%s_id' % opts.parent_attr) or '-',
10
... getattr(n, opts.tree_id_attr), getattr(n, opts.level_attr),
11
... getattr(n, opts.left_attr), getattr(n, opts.right_attr)) \
15
>>> mptt.register(Genre)
16
Traceback (most recent call last):
18
AlreadyRegistered: The model Genre has already been registered.
20
# Creation ####################################################################
21
>>> action = Genre.objects.create(name='Action')
22
>>> platformer = Genre.objects.create(name='Platformer', parent=action)
23
>>> platformer_2d = Genre.objects.create(name='2D Platformer', parent=platformer)
24
>>> platformer = Genre.objects.get(pk=platformer.pk)
25
>>> platformer_3d = Genre.objects.create(name='3D Platformer', parent=platformer)
26
>>> platformer = Genre.objects.get(pk=platformer.pk)
27
>>> platformer_4d = Genre.objects.create(name='4D Platformer', parent=platformer)
28
>>> rpg = Genre.objects.create(name='Role-playing Game')
29
>>> arpg = Genre.objects.create(name='Action RPG', parent=rpg)
30
>>> rpg = Genre.objects.get(pk=rpg.pk)
31
>>> trpg = Genre.objects.create(name='Tactical RPG', parent=rpg)
32
>>> print_tree_details(Genre.tree.all())
42
# Utilities ###################################################################
43
>>> from mptt.utils import previous_current_next, tree_item_iterator, drilldown_tree_for_node
45
>>> for p,c,n in previous_current_next(Genre.tree.all()):
47
(None, <Genre: Action>, <Genre: Platformer>)
48
(<Genre: Action>, <Genre: Platformer>, <Genre: 2D Platformer>)
49
(<Genre: Platformer>, <Genre: 2D Platformer>, <Genre: 3D Platformer>)
50
(<Genre: 2D Platformer>, <Genre: 3D Platformer>, <Genre: 4D Platformer>)
51
(<Genre: 3D Platformer>, <Genre: 4D Platformer>, <Genre: Role-playing Game>)
52
(<Genre: 4D Platformer>, <Genre: Role-playing Game>, <Genre: Action RPG>)
53
(<Genre: Role-playing Game>, <Genre: Action RPG>, <Genre: Tactical RPG>)
54
(<Genre: Action RPG>, <Genre: Tactical RPG>, None)
56
>>> for i,s in tree_item_iterator(Genre.tree.all()):
57
... print (i, s['new_level'], s['closed_levels'])
58
(<Genre: Action>, True, [])
59
(<Genre: Platformer>, True, [])
60
(<Genre: 2D Platformer>, True, [])
61
(<Genre: 3D Platformer>, False, [])
62
(<Genre: 4D Platformer>, False, [2, 1])
63
(<Genre: Role-playing Game>, False, [])
64
(<Genre: Action RPG>, True, [])
65
(<Genre: Tactical RPG>, False, [1, 0])
67
>>> for i,s in tree_item_iterator(Genre.tree.all(), ancestors=True):
68
... print (i, s['new_level'], s['ancestors'], s['closed_levels'])
69
(<Genre: Action>, True, [], [])
70
(<Genre: Platformer>, True, [u'Action'], [])
71
(<Genre: 2D Platformer>, True, [u'Action', u'Platformer'], [])
72
(<Genre: 3D Platformer>, False, [u'Action', u'Platformer'], [])
73
(<Genre: 4D Platformer>, False, [u'Action', u'Platformer'], [2, 1])
74
(<Genre: Role-playing Game>, False, [], [])
75
(<Genre: Action RPG>, True, [u'Role-playing Game'], [])
76
(<Genre: Tactical RPG>, False, [u'Role-playing Game'], [1, 0])
78
>>> action = Genre.objects.get(pk=action.pk)
79
>>> [item.name for item in drilldown_tree_for_node(action)]
80
[u'Action', u'Platformer']
82
>>> platformer = Genre.objects.get(pk=platformer.pk)
83
>>> [item.name for item in drilldown_tree_for_node(platformer)]
84
[u'Action', u'Platformer', u'2D Platformer', u'3D Platformer', u'4D Platformer']
86
>>> platformer_3d = Genre.objects.get(pk=platformer_3d.pk)
87
>>> [item.name for item in drilldown_tree_for_node(platformer_3d)]
88
[u'Action', u'Platformer', u'3D Platformer']
90
# TreeManager Methods #########################################################
92
>>> Genre.tree.root_node(action.tree_id)
94
>>> Genre.tree.root_node(rpg.tree_id)
95
<Genre: Role-playing Game>
96
>>> Genre.tree.root_node(3)
97
Traceback (most recent call last):
99
DoesNotExist: Genre matching query does not exist.
101
>>> [g.name for g in Genre.tree.root_nodes()]
102
[u'Action', u'Role-playing Game']
104
# Model Instance Methods ######################################################
105
>>> action = Genre.objects.get(pk=action.pk)
106
>>> [g.name for g in action.get_ancestors()]
108
>>> [g.name for g in action.get_ancestors(ascending=True)]
110
>>> [g.name for g in action.get_children()]
112
>>> [g.name for g in action.get_descendants()]
113
[u'Platformer', u'2D Platformer', u'3D Platformer', u'4D Platformer']
114
>>> [g.name for g in action.get_descendants(include_self=True)]
115
[u'Action', u'Platformer', u'2D Platformer', u'3D Platformer', u'4D Platformer']
116
>>> action.get_descendant_count()
118
>>> action.get_previous_sibling()
119
>>> action.get_next_sibling()
120
<Genre: Role-playing Game>
121
>>> action.get_root()
123
>>> [g.name for g in action.get_siblings()]
124
[u'Role-playing Game']
125
>>> [g.name for g in action.get_siblings(include_self=True)]
126
[u'Action', u'Role-playing Game']
127
>>> action.is_root_node()
129
>>> action.is_child_node()
131
>>> action.is_leaf_node()
134
>>> platformer = Genre.objects.get(pk=platformer.pk)
135
>>> [g.name for g in platformer.get_ancestors()]
137
>>> [g.name for g in platformer.get_ancestors(ascending=True)]
139
>>> [g.name for g in platformer.get_children()]
140
[u'2D Platformer', u'3D Platformer', u'4D Platformer']
141
>>> [g.name for g in platformer.get_descendants()]
142
[u'2D Platformer', u'3D Platformer', u'4D Platformer']
143
>>> [g.name for g in platformer.get_descendants(include_self=True)]
144
[u'Platformer', u'2D Platformer', u'3D Platformer', u'4D Platformer']
145
>>> platformer.get_descendant_count()
147
>>> platformer.get_previous_sibling()
148
>>> platformer.get_next_sibling()
149
>>> platformer.get_root()
151
>>> [g.name for g in platformer.get_siblings()]
153
>>> [g.name for g in platformer.get_siblings(include_self=True)]
155
>>> platformer.is_root_node()
157
>>> platformer.is_child_node()
159
>>> platformer.is_leaf_node()
162
>>> platformer_3d = Genre.objects.get(pk=platformer_3d.pk)
163
>>> [g.name for g in platformer_3d.get_ancestors()]
164
[u'Action', u'Platformer']
165
>>> [g.name for g in platformer_3d.get_ancestors(ascending=True)]
166
[u'Platformer', u'Action']
167
>>> [g.name for g in platformer_3d.get_children()]
169
>>> [g.name for g in platformer_3d.get_descendants()]
171
>>> [g.name for g in platformer_3d.get_descendants(include_self=True)]
173
>>> platformer_3d.get_descendant_count()
175
>>> platformer_3d.get_previous_sibling()
176
<Genre: 2D Platformer>
177
>>> platformer_3d.get_next_sibling()
178
<Genre: 4D Platformer>
179
>>> platformer_3d.get_root()
181
>>> [g.name for g in platformer_3d.get_siblings()]
182
[u'2D Platformer', u'4D Platformer']
183
>>> [g.name for g in platformer_3d.get_siblings(include_self=True)]
184
[u'2D Platformer', u'3D Platformer', u'4D Platformer']
185
>>> platformer_3d.is_root_node()
187
>>> platformer_3d.is_child_node()
189
>>> platformer_3d.is_leaf_node()
192
# The move_to method will be used in a few places in other tests to verify that
193
# it calls the TreeManager correctly.
195
# Moving Nodes Manually #######################################################
196
>>> games = Category.objects.create(name='PC & Video Games')
197
>>> wii = Category.objects.create(name='Nintendo Wii', parent=games)
198
>>> wii_games = Category.objects.create(name='Games', parent=wii)
199
>>> wii = Category.objects.get(pk=wii.pk)
200
>>> wii_hardware = Category.objects.create(name='Hardware & Accessories', parent=wii)
201
>>> games = Category.objects.get(pk=games.pk)
202
>>> xbox360 = Category.objects.create(name='Xbox 360', parent=games)
203
>>> xbox360_games = Category.objects.create(name='Games', parent=xbox360)
204
>>> xbox360 = Category.objects.get(pk=xbox360.pk)
205
>>> xbox360_hardware = Category.objects.create(name='Hardware & Accessories', parent=xbox360)
206
>>> games = Category.objects.get(pk=games.pk)
207
>>> ps3 = Category.objects.create(name='PlayStation 3', parent=games)
208
>>> ps3_games = Category.objects.create(name='Games', parent=ps3)
209
>>> ps3 = Category.objects.get(pk=ps3.pk)
210
>>> ps3_hardware = Category.objects.create(name='Hardware & Accessories', parent=ps3)
211
>>> print_tree_details(Category.tree.all())
223
>>> wii = Category.objects.get(pk=wii.pk)
224
>>> wii.move_to(None)
225
>>> print_tree_details([wii])
227
>>> print_tree_details(Category.tree.all())
239
>>> games = Category.objects.get(pk=games.pk)
240
>>> Category.tree.move_node(wii, games)
241
>>> print_tree_details([wii])
243
>>> print_tree_details(Category.tree.all())
255
>>> ps3 = Category.objects.get(pk=ps3.pk)
256
>>> Category.tree.move_node(wii, ps3)
257
>>> print_tree_details([wii])
259
>>> print_tree_details(Category.tree.all())
271
>>> ps3 = Category.objects.get(pk=ps3.pk)
272
>>> Category.tree.move_node(ps3, None)
273
>>> print_tree_details([ps3])
275
>>> print_tree_details(Category.tree.all())
287
>>> wii = Category.objects.get(pk=wii.pk)
288
>>> games = Category.objects.get(pk=games.pk)
289
>>> Category.tree.move_node(wii, games)
290
>>> print_tree_details([wii])
292
>>> print_tree_details(Category.tree.all())
304
# Regression test for no level change being required
305
>>> xbox360_games = Category.objects.get(pk=xbox360_games.pk)
306
>>> Category.tree.move_node(xbox360_games, wii)
307
>>> print_tree_details([xbox360_games])
309
>>> print_tree_details(Category.tree.all())
321
#######################
322
# Intra-Tree Movement #
323
#######################
325
>>> root = Node.objects.create()
326
>>> c_1 = Node.objects.create(parent=root)
327
>>> c_1_1 = Node.objects.create(parent=c_1)
328
>>> c_1 = Node.objects.get(pk=c_1.pk)
329
>>> c_1_2 = Node.objects.create(parent=c_1)
330
>>> root = Node.objects.get(pk=root.pk)
331
>>> c_2 = Node.objects.create(parent=root)
332
>>> c_2_1 = Node.objects.create(parent=c_2)
333
>>> c_2 = Node.objects.get(pk=c_2.pk)
334
>>> c_2_2 = Node.objects.create(parent=c_2)
335
>>> print_tree_details(Node.tree.all())
344
# Validate exceptions are raised appropriately
345
>>> root = Node.objects.get(pk=root.pk)
346
>>> Node.tree.move_node(root, root, position='first-child')
347
Traceback (most recent call last):
349
InvalidMove: A node may not be made a child of itself.
350
>>> c_1 = Node.objects.get(pk=c_1.pk)
351
>>> c_1_1 = Node.objects.get(pk=c_1_1.pk)
352
>>> Node.tree.move_node(c_1, c_1_1, position='last-child')
353
Traceback (most recent call last):
355
InvalidMove: A node may not be made a child of any of its descendants.
356
>>> Node.tree.move_node(root, root, position='right')
357
Traceback (most recent call last):
359
InvalidMove: A node may not be made a sibling of itself.
360
>>> c_2 = Node.objects.get(pk=c_2.pk)
361
>>> Node.tree.move_node(c_1, c_1_1, position='left')
362
Traceback (most recent call last):
364
InvalidMove: A node may not be made a sibling of any of its descendants.
365
>>> Node.tree.move_node(c_1, c_2, position='cheese')
366
Traceback (most recent call last):
368
ValueError: An invalid position was given: cheese.
370
# Move up the tree using first-child
371
>>> c_2_2 = Node.objects.get(pk=c_2_2.pk)
372
>>> c_1 = Node.objects.get(pk=c_1.pk)
373
>>> Node.tree.move_node(c_2_2, c_1, 'first-child')
374
>>> print_tree_details([c_2_2])
376
>>> print_tree_details(Node.tree.all())
385
# Undo the move using right
386
>>> c_2_1 = Node.objects.get(pk=c_2_1.pk)
387
>>> c_2_2.move_to(c_2_1, 'right')
388
>>> print_tree_details([c_2_2])
390
>>> print_tree_details(Node.tree.all())
399
# Move up the tree with descendants using first-child
400
>>> c_2 = Node.objects.get(pk=c_2.pk)
401
>>> c_1 = Node.objects.get(pk=c_1.pk)
402
>>> Node.tree.move_node(c_2, c_1, 'first-child')
403
>>> print_tree_details([c_2])
405
>>> print_tree_details(Node.tree.all())
414
# Undo the move using right
415
>>> c_1 = Node.objects.get(pk=c_1.pk)
416
>>> Node.tree.move_node(c_2, c_1, 'right')
417
>>> print_tree_details([c_2])
419
>>> print_tree_details(Node.tree.all())
428
COVERAGE | U1 | U> | D1 | D>
429
------------+----+----+----+----
430
first-child | Y | Y | |
435
# Move down the tree using first-child
436
>>> c_1_2 = Node.objects.get(pk=c_1_2.pk)
437
>>> c_2 = Node.objects.get(pk=c_2.pk)
438
>>> Node.tree.move_node(c_1_2, c_2, 'first-child')
439
>>> print_tree_details([c_1_2])
441
>>> print_tree_details(Node.tree.all())
450
# Undo the move using last-child
451
>>> c_1 = Node.objects.get(pk=c_1.pk)
452
>>> Node.tree.move_node(c_1_2, c_1, 'last-child')
453
>>> print_tree_details([c_1_2])
455
>>> print_tree_details(Node.tree.all())
464
# Move down the tree with descendants using first-child
465
>>> c_1 = Node.objects.get(pk=c_1.pk)
466
>>> c_2 = Node.objects.get(pk=c_2.pk)
467
>>> Node.tree.move_node(c_1, c_2, 'first-child')
468
>>> print_tree_details([c_1])
470
>>> print_tree_details(Node.tree.all())
479
# Undo the move using left
480
>>> c_2 = Node.objects.get(pk=c_2.pk)
481
>>> Node.tree.move_node(c_1, c_2, 'left')
482
>>> print_tree_details([c_1])
484
>>> print_tree_details(Node.tree.all())
493
COVERAGE | U1 | U> | D1 | D>
494
------------+----+----+----+----
495
first-child | Y | Y | Y | Y
500
# Move up the tree using right
501
>>> c_2_2 = Node.objects.get(pk=c_2_2.pk)
502
>>> c_1_1 = Node.objects.get(pk=c_1_1.pk)
503
>>> Node.tree.move_node(c_2_2, c_1_1, 'right')
504
>>> print_tree_details([c_2_2])
506
>>> print_tree_details(Node.tree.all())
515
# Undo the move using last-child
516
>>> c_2 = Node.objects.get(pk=c_2.pk)
517
>>> Node.tree.move_node(c_2_2, c_2, 'last-child')
518
>>> print_tree_details([c_2_2])
520
>>> print_tree_details(Node.tree.all())
529
# Move up the tree with descendants using right
530
>>> c_2 = Node.objects.get(pk=c_2.pk)
531
>>> c_1_1 = Node.objects.get(pk=c_1_1.pk)
532
>>> Node.tree.move_node(c_2, c_1_1, 'right')
533
>>> print_tree_details([c_2])
535
>>> print_tree_details(Node.tree.all())
544
# Undo the move using last-child
545
>>> root = Node.objects.get(pk=root.pk)
546
>>> Node.tree.move_node(c_2, root, 'last-child')
547
>>> print_tree_details([c_2])
549
>>> print_tree_details(Node.tree.all())
558
COVERAGE | U1 | U> | D1 | D>
559
------------+----+----+----+----
560
first-child | Y | Y | Y | Y
561
last-child | Y | | Y | Y
563
right | Y | Y | Y | Y
565
# Move down the tree with descendants using left
566
>>> c_1 = Node.objects.get(pk=c_1.pk)
567
>>> c_2_2 = Node.objects.get(pk=c_2_2.pk)
568
>>> Node.tree.move_node(c_1, c_2_2, 'left')
569
>>> print_tree_details([c_1])
571
>>> print_tree_details(Node.tree.all())
580
# Undo the move using first-child
581
>>> root = Node.objects.get(pk=root.pk)
582
>>> Node.tree.move_node(c_1, root, 'first-child')
583
>>> print_tree_details([c_1])
585
>>> print_tree_details(Node.tree.all())
594
# Move down the tree using left
595
>>> c_1_1 = Node.objects.get(pk=c_1_1.pk)
596
>>> c_2_2 = Node.objects.get(pk=c_2_2.pk)
597
>>> Node.tree.move_node(c_1_1, c_2_2, 'left')
598
>>> print_tree_details([c_1_1])
600
>>> print_tree_details(Node.tree.all())
609
# Undo the move using left
610
>>> c_1_2 = Node.objects.get(pk=c_1_2.pk)
611
>>> Node.tree.move_node(c_1_1, c_1_2, 'left')
612
>>> print_tree_details([c_1_1])
614
>>> print_tree_details(Node.tree.all())
623
COVERAGE | U1 | U> | D1 | D>
624
------------+----+----+----+----
625
first-child | Y | Y | Y | Y
626
last-child | Y | Y | Y | Y
628
right | Y | Y | Y | Y
630
I guess we're covered :)
632
#######################
633
# Inter-Tree Movement #
634
#######################
636
>>> new_root = Node.objects.create()
637
>>> print_tree_details(Node.tree.all())
647
# Moving child nodes between trees ############################################
649
# Move using default (last-child)
650
>>> c_2 = Node.objects.get(pk=c_2.pk)
651
>>> c_2.move_to(new_root)
652
>>> print_tree_details([c_2])
654
>>> print_tree_details(Node.tree.all())
665
>>> c_1_1 = Node.objects.get(pk=c_1_1.pk)
666
>>> c_2 = Node.objects.get(pk=c_2.pk)
667
>>> Node.tree.move_node(c_1_1, c_2, position='left')
668
>>> print_tree_details([c_1_1])
670
>>> print_tree_details(Node.tree.all())
680
# Move using first-child
681
>>> c_1_2 = Node.objects.get(pk=c_1_2.pk)
682
>>> c_2 = Node.objects.get(pk=c_2.pk)
683
>>> Node.tree.move_node(c_1_2, c_2, position='first-child')
684
>>> print_tree_details([c_1_2])
686
>>> print_tree_details(Node.tree.all())
697
>>> c_2 = Node.objects.get(pk=c_2.pk)
698
>>> c_1 = Node.objects.get(pk=c_1.pk)
699
>>> Node.tree.move_node(c_2, c_1, position='right')
700
>>> print_tree_details([c_2])
702
>>> print_tree_details(Node.tree.all())
712
# Move using last-child
713
>>> c_1_1 = Node.objects.get(pk=c_1_1.pk)
714
>>> Node.tree.move_node(c_1_1, c_2, position='last-child')
715
>>> print_tree_details([c_1_1])
717
>>> print_tree_details(Node.tree.all())
727
# Moving a root node into another tree as a child node ########################
729
# Validate exceptions are raised appropriately
730
>>> Node.tree.move_node(root, c_1, position='first-child')
731
Traceback (most recent call last):
733
InvalidMove: A node may not be made a child of any of its descendants.
734
>>> Node.tree.move_node(new_root, c_1, position='cheese')
735
Traceback (most recent call last):
737
ValueError: An invalid position was given: cheese.
739
>>> new_root = Node.objects.get(pk=new_root.pk)
740
>>> c_2 = Node.objects.get(pk=c_2.pk)
741
>>> new_root.move_to(c_2, position='first-child')
742
>>> print_tree_details([new_root])
744
>>> print_tree_details(Node.tree.all())
754
>>> new_root = Node.objects.create()
755
>>> root = Node.objects.get(pk=root.pk)
756
>>> Node.tree.move_node(new_root, root, position='last-child')
757
>>> print_tree_details([new_root])
759
>>> print_tree_details(Node.tree.all())
770
>>> new_root = Node.objects.create()
771
>>> c_2_1 = Node.objects.get(pk=c_2_1.pk)
772
>>> Node.tree.move_node(new_root, c_2_1, position='left')
773
>>> print_tree_details([new_root])
775
>>> print_tree_details(Node.tree.all())
787
>>> new_root = Node.objects.create()
788
>>> c_1 = Node.objects.get(pk=c_1.pk)
789
>>> Node.tree.move_node(new_root, c_1, position='right')
790
>>> print_tree_details([new_root])
792
>>> print_tree_details(Node.tree.all())
805
# Making nodes siblings of root nodes #########################################
807
# Validate exceptions are raised appropriately
808
>>> root = Node.objects.get(pk=root.pk)
809
>>> Node.tree.move_node(root, root, position='left')
810
Traceback (most recent call last):
812
InvalidMove: A node may not be made a sibling of itself.
813
>>> Node.tree.move_node(root, root, position='right')
814
Traceback (most recent call last):
816
InvalidMove: A node may not be made a sibling of itself.
818
>>> r1 = Tree.objects.create()
819
>>> c1_1 = Tree.objects.create(parent=r1)
820
>>> c1_1_1 = Tree.objects.create(parent=c1_1)
821
>>> r2 = Tree.objects.create()
822
>>> c2_1 = Tree.objects.create(parent=r2)
823
>>> c2_1_1 = Tree.objects.create(parent=c2_1)
824
>>> r3 = Tree.objects.create()
825
>>> c3_1 = Tree.objects.create(parent=r3)
826
>>> c3_1_1 = Tree.objects.create(parent=c3_1)
827
>>> print_tree_details(Tree.tree.all())
838
# Target < root node, left sibling
839
>>> r1 = Tree.objects.get(pk=r1.pk)
840
>>> r2 = Tree.objects.get(pk=r2.pk)
841
>>> r2.move_to(r1, 'left')
842
>>> print_tree_details([r2])
844
>>> print_tree_details(Tree.tree.all())
855
# Target > root node, left sibling
856
>>> r3 = Tree.objects.get(pk=r3.pk)
857
>>> r2.move_to(r3, 'left')
858
>>> print_tree_details([r2])
860
>>> print_tree_details(Tree.tree.all())
871
# Target < root node, right sibling
872
>>> r1 = Tree.objects.get(pk=r1.pk)
873
>>> r3 = Tree.objects.get(pk=r3.pk)
874
>>> r3.move_to(r1, 'right')
875
>>> print_tree_details([r3])
877
>>> print_tree_details(Tree.tree.all())
888
# Target > root node, right sibling
889
>>> r1 = Tree.objects.get(pk=r1.pk)
890
>>> r2 = Tree.objects.get(pk=r2.pk)
891
>>> r1.move_to(r2, 'right')
892
>>> print_tree_details([r1])
894
>>> print_tree_details(Tree.tree.all())
905
# No-op, root left sibling
906
>>> r2 = Tree.objects.get(pk=r2.pk)
907
>>> r2.move_to(r1, 'left')
908
>>> print_tree_details([r2])
910
>>> print_tree_details(Tree.tree.all())
921
# No-op, root right sibling
922
>>> r1.move_to(r2, 'right')
923
>>> print_tree_details([r1])
925
>>> print_tree_details(Tree.tree.all())
936
# Child node, left sibling
937
>>> c3_1 = Tree.objects.get(pk=c3_1.pk)
938
>>> c3_1.move_to(r1, 'left')
939
>>> print_tree_details([c3_1])
941
>>> print_tree_details(Tree.tree.all())
952
# Child node, right sibling
953
>>> r3 = Tree.objects.get(pk=r3.pk)
954
>>> c1_1 = Tree.objects.get(pk=c1_1.pk)
955
>>> c1_1.move_to(r3, 'right')
956
>>> print_tree_details([c1_1])
958
>>> print_tree_details(Tree.tree.all())
969
# Insertion of positioned nodes ###############################################
970
>>> r1 = Insert.objects.create()
971
>>> r2 = Insert.objects.create()
972
>>> r3 = Insert.objects.create()
973
>>> print_tree_details(Insert.tree.all())
978
>>> r2 = Insert.objects.get(pk=r2.pk)
980
>>> c1 = Insert.tree.insert_node(c1, r2, commit=True)
981
>>> print_tree_details([c1])
983
>>> print_tree_details(Insert.tree.all())
990
Traceback (most recent call last):
992
ValueError: Cannot insert a node which has already been saved.
995
>>> r2 = Insert.objects.get(pk=r2.pk)
997
>>> c2 = Insert.tree.insert_node(c2, r2, position='first-child', commit=True)
998
>>> print_tree_details([c2])
1000
>>> print_tree_details(Insert.tree.all())
1008
>>> c1 = Insert.objects.get(pk=c1.pk)
1010
>>> c3 = Insert.tree.insert_node(c3, c1, position='left', commit=True)
1011
>>> print_tree_details([c3])
1013
>>> print_tree_details(Insert.tree.all())
1023
>>> c4 = Insert.tree.insert_node(c4, c3, position='right', commit=True)
1024
>>> print_tree_details([c4])
1026
>>> print_tree_details(Insert.tree.all())
1036
>>> r2 = Insert.objects.get(pk=r2.pk)
1038
>>> c5 = Insert.tree.insert_node(c5, r2, position='last-child', commit=True)
1039
>>> print_tree_details([c5])
1041
>>> print_tree_details(Insert.tree.all())
1051
# Left sibling of root
1052
>>> r2 = Insert.objects.get(pk=r2.pk)
1054
>>> r4 = Insert.tree.insert_node(r4, r2, position='left', commit=True)
1055
>>> print_tree_details([r4])
1057
>>> print_tree_details(Insert.tree.all())
1068
# Right sibling of root
1069
>>> r2 = Insert.objects.get(pk=r2.pk)
1071
>>> r5 = Insert.tree.insert_node(r5, r2, position='right', commit=True)
1072
>>> print_tree_details([r5])
1074
>>> print_tree_details(Insert.tree.all())
1088
>>> r6 = Insert.tree.insert_node(r6, None, commit=True)
1089
>>> print_tree_details([r6])
1091
>>> print_tree_details(Insert.tree.all())
1104
# order_insertion_by insertion ################################################
1105
>>> r1 = OrderedInsertion.objects.create(name='games')
1108
>>> r2 = OrderedInsertion.objects.create(name='food')
1109
>>> print_tree_details(OrderedInsertion.tree.all())
1113
# Same name - insert after
1114
>>> r3 = OrderedInsertion.objects.create(name='food')
1115
>>> print_tree_details(OrderedInsertion.tree.all())
1120
>>> c1 = OrderedInsertion.objects.create(name='zoo', parent=r3)
1121
>>> print_tree_details(OrderedInsertion.tree.all())
1127
>>> r3 = OrderedInsertion.objects.get(pk=r3.pk)
1128
>>> c2 = OrderedInsertion.objects.create(name='monkey', parent=r3)
1129
>>> print_tree_details(OrderedInsertion.tree.all())
1136
>>> r3 = OrderedInsertion.objects.get(pk=r3.pk)
1137
>>> c3 = OrderedInsertion.objects.create(name='animal', parent=r3)
1138
>>> print_tree_details(OrderedInsertion.tree.all())
1146
# order_insertion_by reparenting ##############################################
1149
>>> r1 = OrderedInsertion.objects.get(pk=r1.pk)
1150
>>> r3 = OrderedInsertion.objects.get(pk=r3.pk)
1153
>>> print_tree_details(OrderedInsertion.tree.all())
1162
>>> c3 = OrderedInsertion.objects.get(pk=c3.pk)
1163
>>> c3.parent = None
1165
>>> print_tree_details(OrderedInsertion.tree.all())
1174
>>> c1 = OrderedInsertion.objects.get(pk=c1.pk)
1177
>>> print_tree_details(OrderedInsertion.tree.all())
1184
>>> c3 = OrderedInsertion.objects.get(pk=c3.pk)
1185
>>> c2 = OrderedInsertion.objects.get(pk=c2.pk)
1188
>>> print_tree_details(OrderedInsertion.tree.all())
1196
# Insertion of positioned nodes, multiple ordering criteria ###################
1197
>>> r1 = MultiOrder.objects.create(name='fff', size=20, date=date(2008, 1, 1))
1199
# Root nodes - ordering by subsequent fields
1200
>>> r2 = MultiOrder.objects.create(name='fff', size=10, date=date(2009, 1, 1))
1201
>>> print_tree_details(MultiOrder.tree.all())
1205
>>> r3 = MultiOrder.objects.create(name='fff', size=20, date=date(2007, 1, 1))
1206
>>> print_tree_details(MultiOrder.tree.all())
1211
>>> r4 = MultiOrder.objects.create(name='fff', size=20, date=date(2008, 1, 1))
1212
>>> print_tree_details(MultiOrder.tree.all())
1218
>>> r5 = MultiOrder.objects.create(name='fff', size=20, date=date(2007, 1, 1))
1219
>>> print_tree_details(MultiOrder.tree.all())
1226
>>> r6 = MultiOrder.objects.create(name='aaa', size=999, date=date(2010, 1, 1))
1227
>>> print_tree_details(MultiOrder.tree.all())
1236
>>> r1 = MultiOrder.objects.get(pk=r1.pk)
1237
>>> c1 = MultiOrder.objects.create(parent=r1, name='hhh', size=10, date=date(2009, 1, 1))
1238
>>> print_tree_details(MultiOrder.tree.filter(tree_id=r1.tree_id))
1242
>>> r1 = MultiOrder.objects.get(pk=r1.pk)
1243
>>> c2 = MultiOrder.objects.create(parent=r1, name='hhh', size=20, date=date(2008, 1, 1))
1244
>>> print_tree_details(MultiOrder.tree.filter(tree_id=r1.tree_id))
1249
>>> r1 = MultiOrder.objects.get(pk=r1.pk)
1250
>>> c3 = MultiOrder.objects.create(parent=r1, name='hhh', size=15, date=date(2008, 1, 1))
1251
>>> print_tree_details(MultiOrder.tree.filter(tree_id=r1.tree_id))
1257
>>> r1 = MultiOrder.objects.get(pk=r1.pk)
1258
>>> c4 = MultiOrder.objects.create(parent=r1, name='hhh', size=15, date=date(2008, 1, 1))
1259
>>> print_tree_details(MultiOrder.tree.filter(tree_id=r1.tree_id))