~vcs-imports/django-mptt/trunk

« back to all changes in this revision

Viewing changes to mptt/tests/doctests.py

  • Committer: jonathan.buchanan
  • Date: 2008-10-13 22:33:33 UTC
  • Revision ID: vcs-imports@canonical.com-20081013223333-lfxkg5uqyooshv6b
Fixed issue 23 - calling delete() on a tree node now only performs tree management once, as expected; includes an in-progress refactor of the tests which includes a regression test for this issue. Thanks to mara.dragan and jeroen.vloothuis for testcases and patches which demonstrated the issue and an idea for a fix.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
r"""
 
2
>>> from datetime import date
 
3
>>> from mptt.exceptions import InvalidMove
 
4
>>> from mptt.tests.models import Category, Genre, Insert, MultiOrder, Node, OrderedInsertion, Tree
 
5
 
 
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)) \
 
12
...                      for n in nodes])
 
13
 
 
14
>>> import mptt
 
15
>>> mptt.register(Genre)
 
16
Traceback (most recent call last):
 
17
    ...
 
18
AlreadyRegistered: The model Genre has already been registered.
 
19
 
 
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())
 
33
1 - 1 0 1 10
 
34
2 1 1 1 2 9
 
35
3 2 1 2 3 4
 
36
4 2 1 2 5 6
 
37
5 2 1 2 7 8
 
38
6 - 2 0 1 6
 
39
7 6 2 1 2 3
 
40
8 6 2 1 4 5
 
41
 
 
42
# Utilities ###################################################################
 
43
>>> from mptt.utils import previous_current_next, tree_item_iterator, drilldown_tree_for_node
 
44
 
 
45
>>> for p,c,n in previous_current_next(Genre.tree.all()):
 
46
...     print (p,c,n)
 
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)
 
55
 
 
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])
 
66
 
 
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])
 
77
 
 
78
>>> action = Genre.objects.get(pk=action.pk)
 
79
>>> [item.name for item in drilldown_tree_for_node(action)]
 
80
[u'Action', u'Platformer']
 
81
 
 
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']
 
85
 
 
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']
 
89
 
 
90
# TreeManager Methods #########################################################
 
91
 
 
92
>>> Genre.tree.root_node(action.tree_id)
 
93
<Genre: Action>
 
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):
 
98
    ...
 
99
DoesNotExist: Genre matching query does not exist.
 
100
 
 
101
>>> [g.name for g in Genre.tree.root_nodes()]
 
102
[u'Action', u'Role-playing Game']
 
103
 
 
104
# Model Instance Methods ######################################################
 
105
>>> action = Genre.objects.get(pk=action.pk)
 
106
>>> [g.name for g in action.get_ancestors()]
 
107
[]
 
108
>>> [g.name for g in action.get_ancestors(ascending=True)]
 
109
[]
 
110
>>> [g.name for g in action.get_children()]
 
111
[u'Platformer']
 
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()
 
117
4
 
118
>>> action.get_previous_sibling()
 
119
>>> action.get_next_sibling()
 
120
<Genre: Role-playing Game>
 
121
>>> action.get_root()
 
122
<Genre: Action>
 
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()
 
128
True
 
129
>>> action.is_child_node()
 
130
False
 
131
>>> action.is_leaf_node()
 
132
False
 
133
 
 
134
>>> platformer = Genre.objects.get(pk=platformer.pk)
 
135
>>> [g.name for g in platformer.get_ancestors()]
 
136
[u'Action']
 
137
>>> [g.name for g in platformer.get_ancestors(ascending=True)]
 
138
[u'Action']
 
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()
 
146
3
 
147
>>> platformer.get_previous_sibling()
 
148
>>> platformer.get_next_sibling()
 
149
>>> platformer.get_root()
 
150
<Genre: Action>
 
151
>>> [g.name for g in platformer.get_siblings()]
 
152
[]
 
153
>>> [g.name for g in platformer.get_siblings(include_self=True)]
 
154
[u'Platformer']
 
155
>>> platformer.is_root_node()
 
156
False
 
157
>>> platformer.is_child_node()
 
158
True
 
159
>>> platformer.is_leaf_node()
 
160
False
 
161
 
 
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()]
 
168
[]
 
169
>>> [g.name for g in platformer_3d.get_descendants()]
 
170
[]
 
171
>>> [g.name for g in platformer_3d.get_descendants(include_self=True)]
 
172
[u'3D Platformer']
 
173
>>> platformer_3d.get_descendant_count()
 
174
0
 
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()
 
180
<Genre: Action>
 
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()
 
186
False
 
187
>>> platformer_3d.is_child_node()
 
188
True
 
189
>>> platformer_3d.is_leaf_node()
 
190
True
 
191
 
 
192
# The move_to method will be used in a few places in other tests to verify that
 
193
# it calls the TreeManager correctly.
 
194
 
 
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())
 
212
1 - 1 0 1 20
 
213
2 1 1 1 2 7
 
214
3 2 1 2 3 4
 
215
4 2 1 2 5 6
 
216
5 1 1 1 8 13
 
217
6 5 1 2 9 10
 
218
7 5 1 2 11 12
 
219
8 1 1 1 14 19
 
220
9 8 1 2 15 16
 
221
10 8 1 2 17 18
 
222
 
 
223
>>> wii = Category.objects.get(pk=wii.pk)
 
224
>>> wii.move_to(None)
 
225
>>> print_tree_details([wii])
 
226
2 - 2 0 1 6
 
227
>>> print_tree_details(Category.tree.all())
 
228
1 - 1 0 1 14
 
229
5 1 1 1 2 7
 
230
6 5 1 2 3 4
 
231
7 5 1 2 5 6
 
232
8 1 1 1 8 13
 
233
9 8 1 2 9 10
 
234
10 8 1 2 11 12
 
235
2 - 2 0 1 6
 
236
3 2 2 1 2 3
 
237
4 2 2 1 4 5
 
238
 
 
239
>>> games = Category.objects.get(pk=games.pk)
 
240
>>> Category.tree.move_node(wii, games)
 
241
>>> print_tree_details([wii])
 
242
2 1 1 1 14 19
 
243
>>> print_tree_details(Category.tree.all())
 
244
1 - 1 0 1 20
 
245
5 1 1 1 2 7
 
246
6 5 1 2 3 4
 
247
7 5 1 2 5 6
 
248
8 1 1 1 8 13
 
249
9 8 1 2 9 10
 
250
10 8 1 2 11 12
 
251
2 1 1 1 14 19
 
252
3 2 1 2 15 16
 
253
4 2 1 2 17 18
 
254
 
 
255
>>> ps3 = Category.objects.get(pk=ps3.pk)
 
256
>>> Category.tree.move_node(wii, ps3)
 
257
>>> print_tree_details([wii])
 
258
2 8 1 2 13 18
 
259
>>> print_tree_details(Category.tree.all())
 
260
1 - 1 0 1 20
 
261
5 1 1 1 2 7
 
262
6 5 1 2 3 4
 
263
7 5 1 2 5 6
 
264
8 1 1 1 8 19
 
265
9 8 1 2 9 10
 
266
10 8 1 2 11 12
 
267
2 8 1 2 13 18
 
268
3 2 1 3 14 15
 
269
4 2 1 3 16 17
 
270
 
 
271
>>> ps3 = Category.objects.get(pk=ps3.pk)
 
272
>>> Category.tree.move_node(ps3, None)
 
273
>>> print_tree_details([ps3])
 
274
8 - 2 0 1 12
 
275
>>> print_tree_details(Category.tree.all())
 
276
1 - 1 0 1 8
 
277
5 1 1 1 2 7
 
278
6 5 1 2 3 4
 
279
7 5 1 2 5 6
 
280
8 - 2 0 1 12
 
281
9 8 2 1 2 3
 
282
10 8 2 1 4 5
 
283
2 8 2 1 6 11
 
284
3 2 2 2 7 8
 
285
4 2 2 2 9 10
 
286
 
 
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])
 
291
2 1 1 1 8 13
 
292
>>> print_tree_details(Category.tree.all())
 
293
1 - 1 0 1 14
 
294
5 1 1 1 2 7
 
295
6 5 1 2 3 4
 
296
7 5 1 2 5 6
 
297
2 1 1 1 8 13
 
298
3 2 1 2 9 10
 
299
4 2 1 2 11 12
 
300
8 - 2 0 1 6
 
301
9 8 2 1 2 3
 
302
10 8 2 1 4 5
 
303
 
 
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])
 
308
6 2 1 2 11 12
 
309
>>> print_tree_details(Category.tree.all())
 
310
1 - 1 0 1 14
 
311
5 1 1 1 2 5
 
312
7 5 1 2 3 4
 
313
2 1 1 1 6 13
 
314
3 2 1 2 7 8
 
315
4 2 1 2 9 10
 
316
6 2 1 2 11 12
 
317
8 - 2 0 1 6
 
318
9 8 2 1 2 3
 
319
10 8 2 1 4 5
 
320
 
 
321
#######################
 
322
# Intra-Tree Movement #
 
323
#######################
 
324
 
 
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())
 
336
1 - 1 0 1 14
 
337
2 1 1 1 2 7
 
338
3 2 1 2 3 4
 
339
4 2 1 2 5 6
 
340
5 1 1 1 8 13
 
341
6 5 1 2 9 10
 
342
7 5 1 2 11 12
 
343
 
 
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):
 
348
    ...
 
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):
 
354
    ...
 
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):
 
358
    ...
 
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):
 
363
    ...
 
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):
 
367
    ...
 
368
ValueError: An invalid position was given: cheese.
 
369
 
 
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])
 
375
7 2 1 2 3 4
 
376
>>> print_tree_details(Node.tree.all())
 
377
1 - 1 0 1 14
 
378
2 1 1 1 2 9
 
379
7 2 1 2 3 4
 
380
3 2 1 2 5 6
 
381
4 2 1 2 7 8
 
382
5 1 1 1 10 13
 
383
6 5 1 2 11 12
 
384
 
 
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])
 
389
7 5 1 2 11 12
 
390
>>> print_tree_details(Node.tree.all())
 
391
1 - 1 0 1 14
 
392
2 1 1 1 2 7
 
393
3 2 1 2 3 4
 
394
4 2 1 2 5 6
 
395
5 1 1 1 8 13
 
396
6 5 1 2 9 10
 
397
7 5 1 2 11 12
 
398
 
 
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])
 
404
5 2 1 2 3 8
 
405
>>> print_tree_details(Node.tree.all())
 
406
1 - 1 0 1 14
 
407
2 1 1 1 2 13
 
408
5 2 1 2 3 8
 
409
6 5 1 3 4 5
 
410
7 5 1 3 6 7
 
411
3 2 1 2 9 10
 
412
4 2 1 2 11 12
 
413
 
 
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])
 
418
5 1 1 1 8 13
 
419
>>> print_tree_details(Node.tree.all())
 
420
1 - 1 0 1 14
 
421
2 1 1 1 2 7
 
422
3 2 1 2 3 4
 
423
4 2 1 2 5 6
 
424
5 1 1 1 8 13
 
425
6 5 1 2 9 10
 
426
7 5 1 2 11 12
 
427
 
 
428
COVERAGE    | U1 | U> | D1 | D>
 
429
------------+----+----+----+----
 
430
first-child | Y  | Y  |    |
 
431
last-child  |    |    |    |
 
432
left        |    |    |    |
 
433
right       |    |    | Y  | Y
 
434
 
 
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])
 
440
4 5 1 2 7 8
 
441
>>> print_tree_details(Node.tree.all())
 
442
1 - 1 0 1 14
 
443
2 1 1 1 2 5
 
444
3 2 1 2 3 4
 
445
5 1 1 1 6 13
 
446
4 5 1 2 7 8
 
447
6 5 1 2 9 10
 
448
7 5 1 2 11 12
 
449
 
 
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])
 
454
4 2 1 2 5 6
 
455
>>> print_tree_details(Node.tree.all())
 
456
1 - 1 0 1 14
 
457
2 1 1 1 2 7
 
458
3 2 1 2 3 4
 
459
4 2 1 2 5 6
 
460
5 1 1 1 8 13
 
461
6 5 1 2 9 10
 
462
7 5 1 2 11 12
 
463
 
 
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])
 
469
2 5 1 2 3 8
 
470
>>> print_tree_details(Node.tree.all())
 
471
1 - 1 0 1 14
 
472
5 1 1 1 2 13
 
473
2 5 1 2 3 8
 
474
3 2 1 3 4 5
 
475
4 2 1 3 6 7
 
476
6 5 1 2 9 10
 
477
7 5 1 2 11 12
 
478
 
 
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])
 
483
2 1 1 1 2 7
 
484
>>> print_tree_details(Node.tree.all())
 
485
1 - 1 0 1 14
 
486
2 1 1 1 2 7
 
487
3 2 1 2 3 4
 
488
4 2 1 2 5 6
 
489
5 1 1 1 8 13
 
490
6 5 1 2 9 10
 
491
7 5 1 2 11 12
 
492
 
 
493
COVERAGE    | U1 | U> | D1 | D>
 
494
------------+----+----+----+----
 
495
first-child | Y  | Y  | Y  | Y
 
496
last-child  | Y  |    |    |
 
497
left        |    | Y  |    |
 
498
right       |    |    | Y  | Y
 
499
 
 
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])
 
505
7 2 1 2 5 6
 
506
>>> print_tree_details(Node.tree.all())
 
507
1 - 1 0 1 14
 
508
2 1 1 1 2 9
 
509
3 2 1 2 3 4
 
510
7 2 1 2 5 6
 
511
4 2 1 2 7 8
 
512
5 1 1 1 10 13
 
513
6 5 1 2 11 12
 
514
 
 
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])
 
519
7 5 1 2 11 12
 
520
>>> print_tree_details(Node.tree.all())
 
521
1 - 1 0 1 14
 
522
2 1 1 1 2 7
 
523
3 2 1 2 3 4
 
524
4 2 1 2 5 6
 
525
5 1 1 1 8 13
 
526
6 5 1 2 9 10
 
527
7 5 1 2 11 12
 
528
 
 
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])
 
534
5 2 1 2 5 10
 
535
>>> print_tree_details(Node.tree.all())
 
536
1 - 1 0 1 14
 
537
2 1 1 1 2 13
 
538
3 2 1 2 3 4
 
539
5 2 1 2 5 10
 
540
6 5 1 3 6 7
 
541
7 5 1 3 8 9
 
542
4 2 1 2 11 12
 
543
 
 
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])
 
548
5 1 1 1 8 13
 
549
>>> print_tree_details(Node.tree.all())
 
550
1 - 1 0 1 14
 
551
2 1 1 1 2 7
 
552
3 2 1 2 3 4
 
553
4 2 1 2 5 6
 
554
5 1 1 1 8 13
 
555
6 5 1 2 9 10
 
556
7 5 1 2 11 12
 
557
 
 
558
COVERAGE    | U1 | U> | D1 | D>
 
559
------------+----+----+----+----
 
560
first-child | Y  | Y  | Y  | Y
 
561
last-child  | Y  |    | Y  | Y
 
562
left        |    | Y  |    |
 
563
right       | Y  | Y  | Y  | Y
 
564
 
 
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])
 
570
2 5 1 2 5 10
 
571
>>> print_tree_details(Node.tree.all())
 
572
1 - 1 0 1 14
 
573
5 1 1 1 2 13
 
574
6 5 1 2 3 4
 
575
2 5 1 2 5 10
 
576
3 2 1 3 6 7
 
577
4 2 1 3 8 9
 
578
7 5 1 2 11 12
 
579
 
 
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])
 
584
2 1 1 1 2 7
 
585
>>> print_tree_details(Node.tree.all())
 
586
1 - 1 0 1 14
 
587
2 1 1 1 2 7
 
588
3 2 1 2 3 4
 
589
4 2 1 2 5 6
 
590
5 1 1 1 8 13
 
591
6 5 1 2 9 10
 
592
7 5 1 2 11 12
 
593
 
 
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])
 
599
3 5 1 2 9 10
 
600
>>> print_tree_details(Node.tree.all())
 
601
1 - 1 0 1 14
 
602
2 1 1 1 2 5
 
603
4 2 1 2 3 4
 
604
5 1 1 1 6 13
 
605
6 5 1 2 7 8
 
606
3 5 1 2 9 10
 
607
7 5 1 2 11 12
 
608
 
 
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])
 
613
3 2 1 2 3 4
 
614
>>> print_tree_details(Node.tree.all())
 
615
1 - 1 0 1 14
 
616
2 1 1 1 2 7
 
617
3 2 1 2 3 4
 
618
4 2 1 2 5 6
 
619
5 1 1 1 8 13
 
620
6 5 1 2 9 10
 
621
7 5 1 2 11 12
 
622
 
 
623
COVERAGE    | U1 | U> | D1 | D>
 
624
------------+----+----+----+----
 
625
first-child | Y  | Y  | Y  | Y
 
626
last-child  | Y  | Y  | Y  | Y
 
627
left        | Y  | Y  | Y  | Y
 
628
right       | Y  | Y  | Y  | Y
 
629
 
 
630
I guess we're covered :)
 
631
 
 
632
#######################
 
633
# Inter-Tree Movement #
 
634
#######################
 
635
 
 
636
>>> new_root = Node.objects.create()
 
637
>>> print_tree_details(Node.tree.all())
 
638
1 - 1 0 1 14
 
639
2 1 1 1 2 7
 
640
3 2 1 2 3 4
 
641
4 2 1 2 5 6
 
642
5 1 1 1 8 13
 
643
6 5 1 2 9 10
 
644
7 5 1 2 11 12
 
645
8 - 2 0 1 2
 
646
 
 
647
# Moving child nodes between trees ############################################
 
648
 
 
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])
 
653
5 8 2 1 2 7
 
654
>>> print_tree_details(Node.tree.all())
 
655
1 - 1 0 1 8
 
656
2 1 1 1 2 7
 
657
3 2 1 2 3 4
 
658
4 2 1 2 5 6
 
659
8 - 2 0 1 8
 
660
5 8 2 1 2 7
 
661
6 5 2 2 3 4
 
662
7 5 2 2 5 6
 
663
 
 
664
# Move using left
 
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])
 
669
3 8 2 1 2 3
 
670
>>> print_tree_details(Node.tree.all())
 
671
1 - 1 0 1 6
 
672
2 1 1 1 2 5
 
673
4 2 1 2 3 4
 
674
8 - 2 0 1 10
 
675
3 8 2 1 2 3
 
676
5 8 2 1 4 9
 
677
6 5 2 2 5 6
 
678
7 5 2 2 7 8
 
679
 
 
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])
 
685
4 5 2 2 5 6
 
686
>>> print_tree_details(Node.tree.all())
 
687
1 - 1 0 1 4
 
688
2 1 1 1 2 3
 
689
8 - 2 0 1 12
 
690
3 8 2 1 2 3
 
691
5 8 2 1 4 11
 
692
4 5 2 2 5 6
 
693
6 5 2 2 7 8
 
694
7 5 2 2 9 10
 
695
 
 
696
# Move using right
 
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])
 
701
5 1 1 1 4 11
 
702
>>> print_tree_details(Node.tree.all())
 
703
1 - 1 0 1 12
 
704
2 1 1 1 2 3
 
705
5 1 1 1 4 11
 
706
4 5 1 2 5 6
 
707
6 5 1 2 7 8
 
708
7 5 1 2 9 10
 
709
8 - 2 0 1 4
 
710
3 8 2 1 2 3
 
711
 
 
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])
 
716
3 5 1 2 11 12
 
717
>>> print_tree_details(Node.tree.all())
 
718
1 - 1 0 1 14
 
719
2 1 1 1 2 3
 
720
5 1 1 1 4 13
 
721
4 5 1 2 5 6
 
722
6 5 1 2 7 8
 
723
7 5 1 2 9 10
 
724
3 5 1 2 11 12
 
725
8 - 2 0 1 2
 
726
 
 
727
# Moving a root node into another tree as a child node ########################
 
728
 
 
729
# Validate exceptions are raised appropriately
 
730
>>> Node.tree.move_node(root, c_1, position='first-child')
 
731
Traceback (most recent call last):
 
732
    ...
 
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):
 
736
    ...
 
737
ValueError: An invalid position was given: cheese.
 
738
 
 
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])
 
743
8 5 1 2 5 6
 
744
>>> print_tree_details(Node.tree.all())
 
745
1 - 1 0 1 16
 
746
2 1 1 1 2 3
 
747
5 1 1 1 4 15
 
748
8 5 1 2 5 6
 
749
4 5 1 2 7 8
 
750
6 5 1 2 9 10
 
751
7 5 1 2 11 12
 
752
3 5 1 2 13 14
 
753
 
 
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])
 
758
9 1 1 1 16 17
 
759
>>> print_tree_details(Node.tree.all())
 
760
1 - 1 0 1 18
 
761
2 1 1 1 2 3
 
762
5 1 1 1 4 15
 
763
8 5 1 2 5 6
 
764
4 5 1 2 7 8
 
765
6 5 1 2 9 10
 
766
7 5 1 2 11 12
 
767
3 5 1 2 13 14
 
768
9 1 1 1 16 17
 
769
 
 
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])
 
774
10 5 1 2 9 10
 
775
>>> print_tree_details(Node.tree.all())
 
776
1 - 1 0 1 20
 
777
2 1 1 1 2 3
 
778
5 1 1 1 4 17
 
779
8 5 1 2 5 6
 
780
4 5 1 2 7 8
 
781
10 5 1 2 9 10
 
782
6 5 1 2 11 12
 
783
7 5 1 2 13 14
 
784
3 5 1 2 15 16
 
785
9 1 1 1 18 19
 
786
 
 
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])
 
791
11 1 1 1 4 5
 
792
>>> print_tree_details(Node.tree.all())
 
793
1 - 1 0 1 22
 
794
2 1 1 1 2 3
 
795
11 1 1 1 4 5
 
796
5 1 1 1 6 19
 
797
8 5 1 2 7 8
 
798
4 5 1 2 9 10
 
799
10 5 1 2 11 12
 
800
6 5 1 2 13 14
 
801
7 5 1 2 15 16
 
802
3 5 1 2 17 18
 
803
9 1 1 1 20 21
 
804
 
 
805
# Making nodes siblings of root nodes #########################################
 
806
 
 
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):
 
811
    ...
 
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):
 
815
    ...
 
816
InvalidMove: A node may not be made a sibling of itself.
 
817
 
 
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())
 
828
1 - 1 0 1 6
 
829
2 1 1 1 2 5
 
830
3 2 1 2 3 4
 
831
4 - 2 0 1 6
 
832
5 4 2 1 2 5
 
833
6 5 2 2 3 4
 
834
7 - 3 0 1 6
 
835
8 7 3 1 2 5
 
836
9 8 3 2 3 4
 
837
 
 
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])
 
843
4 - 1 0 1 6
 
844
>>> print_tree_details(Tree.tree.all())
 
845
4 - 1 0 1 6
 
846
5 4 1 1 2 5
 
847
6 5 1 2 3 4
 
848
1 - 2 0 1 6
 
849
2 1 2 1 2 5
 
850
3 2 2 2 3 4
 
851
7 - 3 0 1 6
 
852
8 7 3 1 2 5
 
853
9 8 3 2 3 4
 
854
 
 
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])
 
859
4 - 2 0 1 6
 
860
>>> print_tree_details(Tree.tree.all())
 
861
1 - 1 0 1 6
 
862
2 1 1 1 2 5
 
863
3 2 1 2 3 4
 
864
4 - 2 0 1 6
 
865
5 4 2 1 2 5
 
866
6 5 2 2 3 4
 
867
7 - 3 0 1 6
 
868
8 7 3 1 2 5
 
869
9 8 3 2 3 4
 
870
 
 
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])
 
876
7 - 2 0 1 6
 
877
>>> print_tree_details(Tree.tree.all())
 
878
1 - 1 0 1 6
 
879
2 1 1 1 2 5
 
880
3 2 1 2 3 4
 
881
7 - 2 0 1 6
 
882
8 7 2 1 2 5
 
883
9 8 2 2 3 4
 
884
4 - 3 0 1 6
 
885
5 4 3 1 2 5
 
886
6 5 3 2 3 4
 
887
 
 
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])
 
893
1 - 3 0 1 6
 
894
>>> print_tree_details(Tree.tree.all())
 
895
7 - 1 0 1 6
 
896
8 7 1 1 2 5
 
897
9 8 1 2 3 4
 
898
4 - 2 0 1 6
 
899
5 4 2 1 2 5
 
900
6 5 2 2 3 4
 
901
1 - 3 0 1 6
 
902
2 1 3 1 2 5
 
903
3 2 3 2 3 4
 
904
 
 
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])
 
909
4 - 2 0 1 6
 
910
>>> print_tree_details(Tree.tree.all())
 
911
7 - 1 0 1 6
 
912
8 7 1 1 2 5
 
913
9 8 1 2 3 4
 
914
4 - 2 0 1 6
 
915
5 4 2 1 2 5
 
916
6 5 2 2 3 4
 
917
1 - 3 0 1 6
 
918
2 1 3 1 2 5
 
919
3 2 3 2 3 4
 
920
 
 
921
# No-op, root right sibling
 
922
>>> r1.move_to(r2, 'right')
 
923
>>> print_tree_details([r1])
 
924
1 - 3 0 1 6
 
925
>>> print_tree_details(Tree.tree.all())
 
926
7 - 1 0 1 6
 
927
8 7 1 1 2 5
 
928
9 8 1 2 3 4
 
929
4 - 2 0 1 6
 
930
5 4 2 1 2 5
 
931
6 5 2 2 3 4
 
932
1 - 3 0 1 6
 
933
2 1 3 1 2 5
 
934
3 2 3 2 3 4
 
935
 
 
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])
 
940
8 - 3 0 1 4
 
941
>>> print_tree_details(Tree.tree.all())
 
942
7 - 1 0 1 2
 
943
4 - 2 0 1 6
 
944
5 4 2 1 2 5
 
945
6 5 2 2 3 4
 
946
8 - 3 0 1 4
 
947
9 8 3 1 2 3
 
948
1 - 4 0 1 6
 
949
2 1 4 1 2 5
 
950
3 2 4 2 3 4
 
951
 
 
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])
 
957
2 - 2 0 1 4
 
958
>>> print_tree_details(Tree.tree.all())
 
959
7 - 1 0 1 2
 
960
2 - 2 0 1 4
 
961
3 2 2 1 2 3
 
962
4 - 3 0 1 6
 
963
5 4 3 1 2 5
 
964
6 5 3 2 3 4
 
965
8 - 4 0 1 4
 
966
9 8 4 1 2 3
 
967
1 - 5 0 1 2
 
968
 
 
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())
 
974
1 - 1 0 1 2
 
975
2 - 2 0 1 2
 
976
3 - 3 0 1 2
 
977
 
 
978
>>> r2 = Insert.objects.get(pk=r2.pk)
 
979
>>> c1 = Insert()
 
980
>>> c1 = Insert.tree.insert_node(c1, r2, commit=True)
 
981
>>> print_tree_details([c1])
 
982
4 2 2 1 2 3
 
983
>>> print_tree_details(Insert.tree.all())
 
984
1 - 1 0 1 2
 
985
2 - 2 0 1 4
 
986
4 2 2 1 2 3
 
987
3 - 3 0 1 2
 
988
 
 
989
>>> c1.insert_at(r2)
 
990
Traceback (most recent call last):
 
991
    ...
 
992
ValueError: Cannot insert a node which has already been saved.
 
993
 
 
994
# First child
 
995
>>> r2 = Insert.objects.get(pk=r2.pk)
 
996
>>> c2 = Insert()
 
997
>>> c2 = Insert.tree.insert_node(c2, r2, position='first-child', commit=True)
 
998
>>> print_tree_details([c2])
 
999
5 2 2 1 2 3
 
1000
>>> print_tree_details(Insert.tree.all())
 
1001
1 - 1 0 1 2
 
1002
2 - 2 0 1 6
 
1003
5 2 2 1 2 3
 
1004
4 2 2 1 4 5
 
1005
3 - 3 0 1 2
 
1006
 
 
1007
# Left
 
1008
>>> c1 = Insert.objects.get(pk=c1.pk)
 
1009
>>> c3 = Insert()
 
1010
>>> c3 = Insert.tree.insert_node(c3, c1, position='left', commit=True)
 
1011
>>> print_tree_details([c3])
 
1012
6 2 2 1 4 5
 
1013
>>> print_tree_details(Insert.tree.all())
 
1014
1 - 1 0 1 2
 
1015
2 - 2 0 1 8
 
1016
5 2 2 1 2 3
 
1017
6 2 2 1 4 5
 
1018
4 2 2 1 6 7
 
1019
3 - 3 0 1 2
 
1020
 
 
1021
# Right
 
1022
>>> c4 = Insert()
 
1023
>>> c4 = Insert.tree.insert_node(c4, c3, position='right', commit=True)
 
1024
>>> print_tree_details([c4])
 
1025
7 2 2 1 6 7
 
1026
>>> print_tree_details(Insert.tree.all())
 
1027
1 - 1 0 1 2
 
1028
2 - 2 0 1 10
 
1029
5 2 2 1 2 3
 
1030
6 2 2 1 4 5
 
1031
7 2 2 1 6 7
 
1032
4 2 2 1 8 9
 
1033
3 - 3 0 1 2
 
1034
 
 
1035
# Last child
 
1036
>>> r2 = Insert.objects.get(pk=r2.pk)
 
1037
>>> c5 = Insert()
 
1038
>>> c5 = Insert.tree.insert_node(c5, r2, position='last-child', commit=True)
 
1039
>>> print_tree_details([c5])
 
1040
8 2 2 1 10 11
 
1041
>>> print_tree_details(Insert.tree.all())
 
1042
1 - 1 0 1 2
 
1043
2 - 2 0 1 12
 
1044
5 2 2 1 2 3
 
1045
6 2 2 1 4 5
 
1046
7 2 2 1 6 7
 
1047
4 2 2 1 8 9
 
1048
8 2 2 1 10 11
 
1049
3 - 3 0 1 2
 
1050
 
 
1051
# Left sibling of root
 
1052
>>> r2 = Insert.objects.get(pk=r2.pk)
 
1053
>>> r4 = Insert()
 
1054
>>> r4 = Insert.tree.insert_node(r4, r2, position='left', commit=True)
 
1055
>>> print_tree_details([r4])
 
1056
9 - 2 0 1 2
 
1057
>>> print_tree_details(Insert.tree.all())
 
1058
1 - 1 0 1 2
 
1059
9 - 2 0 1 2
 
1060
2 - 3 0 1 12
 
1061
5 2 3 1 2 3
 
1062
6 2 3 1 4 5
 
1063
7 2 3 1 6 7
 
1064
4 2 3 1 8 9
 
1065
8 2 3 1 10 11
 
1066
3 - 4 0 1 2
 
1067
 
 
1068
# Right sibling of root
 
1069
>>> r2 = Insert.objects.get(pk=r2.pk)
 
1070
>>> r5 = Insert()
 
1071
>>> r5 = Insert.tree.insert_node(r5, r2, position='right', commit=True)
 
1072
>>> print_tree_details([r5])
 
1073
10 - 4 0 1 2
 
1074
>>> print_tree_details(Insert.tree.all())
 
1075
1 - 1 0 1 2
 
1076
9 - 2 0 1 2
 
1077
2 - 3 0 1 12
 
1078
5 2 3 1 2 3
 
1079
6 2 3 1 4 5
 
1080
7 2 3 1 6 7
 
1081
4 2 3 1 8 9
 
1082
8 2 3 1 10 11
 
1083
10 - 4 0 1 2
 
1084
3 - 5 0 1 2
 
1085
 
 
1086
# Last root
 
1087
>>> r6 = Insert()
 
1088
>>> r6 = Insert.tree.insert_node(r6, None, commit=True)
 
1089
>>> print_tree_details([r6])
 
1090
11 - 6 0 1 2
 
1091
>>> print_tree_details(Insert.tree.all())
 
1092
1 - 1 0 1 2
 
1093
9 - 2 0 1 2
 
1094
2 - 3 0 1 12
 
1095
5 2 3 1 2 3
 
1096
6 2 3 1 4 5
 
1097
7 2 3 1 6 7
 
1098
4 2 3 1 8 9
 
1099
8 2 3 1 10 11
 
1100
10 - 4 0 1 2
 
1101
3 - 5 0 1 2
 
1102
11 - 6 0 1 2
 
1103
 
 
1104
# order_insertion_by insertion ################################################
 
1105
>>> r1 = OrderedInsertion.objects.create(name='games')
 
1106
 
 
1107
# Root ordering
 
1108
>>> r2 = OrderedInsertion.objects.create(name='food')
 
1109
>>> print_tree_details(OrderedInsertion.tree.all())
 
1110
2 - 1 0 1 2
 
1111
1 - 2 0 1 2
 
1112
 
 
1113
# Same name - insert after
 
1114
>>> r3 = OrderedInsertion.objects.create(name='food')
 
1115
>>> print_tree_details(OrderedInsertion.tree.all())
 
1116
2 - 1 0 1 2
 
1117
3 - 2 0 1 2
 
1118
1 - 3 0 1 2
 
1119
 
 
1120
>>> c1 = OrderedInsertion.objects.create(name='zoo', parent=r3)
 
1121
>>> print_tree_details(OrderedInsertion.tree.all())
 
1122
2 - 1 0 1 2
 
1123
3 - 2 0 1 4
 
1124
4 3 2 1 2 3
 
1125
1 - 3 0 1 2
 
1126
 
 
1127
>>> r3 = OrderedInsertion.objects.get(pk=r3.pk)
 
1128
>>> c2 = OrderedInsertion.objects.create(name='monkey', parent=r3)
 
1129
>>> print_tree_details(OrderedInsertion.tree.all())
 
1130
2 - 1 0 1 2
 
1131
3 - 2 0 1 6
 
1132
5 3 2 1 2 3
 
1133
4 3 2 1 4 5
 
1134
1 - 3 0 1 2
 
1135
 
 
1136
>>> r3 = OrderedInsertion.objects.get(pk=r3.pk)
 
1137
>>> c3 = OrderedInsertion.objects.create(name='animal', parent=r3)
 
1138
>>> print_tree_details(OrderedInsertion.tree.all())
 
1139
2 - 1 0 1 2
 
1140
3 - 2 0 1 8
 
1141
6 3 2 1 2 3
 
1142
5 3 2 1 4 5
 
1143
4 3 2 1 6 7
 
1144
1 - 3 0 1 2
 
1145
 
 
1146
# order_insertion_by reparenting ##############################################
 
1147
 
 
1148
# Root -> child
 
1149
>>> r1 = OrderedInsertion.objects.get(pk=r1.pk)
 
1150
>>> r3 = OrderedInsertion.objects.get(pk=r3.pk)
 
1151
>>> r1.parent = r3
 
1152
>>> r1.save()
 
1153
>>> print_tree_details(OrderedInsertion.tree.all())
 
1154
2 - 1 0 1 2
 
1155
3 - 2 0 1 10
 
1156
6 3 2 1 2 3
 
1157
1 3 2 1 4 5
 
1158
5 3 2 1 6 7
 
1159
4 3 2 1 8 9
 
1160
 
 
1161
# Child -> root
 
1162
>>> c3 = OrderedInsertion.objects.get(pk=c3.pk)
 
1163
>>> c3.parent = None
 
1164
>>> c3.save()
 
1165
>>> print_tree_details(OrderedInsertion.tree.all())
 
1166
6 - 1 0 1 2
 
1167
2 - 2 0 1 2
 
1168
3 - 3 0 1 8
 
1169
1 3 3 1 2 3
 
1170
5 3 3 1 4 5
 
1171
4 3 3 1 6 7
 
1172
 
 
1173
# Child -> child
 
1174
>>> c1 = OrderedInsertion.objects.get(pk=c1.pk)
 
1175
>>> c1.parent = c3
 
1176
>>> c1.save()
 
1177
>>> print_tree_details(OrderedInsertion.tree.all())
 
1178
6 - 1 0 1 4
 
1179
4 6 1 1 2 3
 
1180
2 - 2 0 1 2
 
1181
3 - 3 0 1 6
 
1182
1 3 3 1 2 3
 
1183
5 3 3 1 4 5
 
1184
>>> c3 = OrderedInsertion.objects.get(pk=c3.pk)
 
1185
>>> c2 = OrderedInsertion.objects.get(pk=c2.pk)
 
1186
>>> c2.parent = c3
 
1187
>>> c2.save()
 
1188
>>> print_tree_details(OrderedInsertion.tree.all())
 
1189
6 - 1 0 1 6
 
1190
5 6 1 1 2 3
 
1191
4 6 1 1 4 5
 
1192
2 - 2 0 1 2
 
1193
3 - 3 0 1 4
 
1194
1 3 3 1 2 3
 
1195
 
 
1196
# Insertion of positioned nodes, multiple ordering criteria ###################
 
1197
>>> r1 = MultiOrder.objects.create(name='fff', size=20, date=date(2008, 1, 1))
 
1198
 
 
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())
 
1202
2 - 1 0 1 2
 
1203
1 - 2 0 1 2
 
1204
 
 
1205
>>> r3 = MultiOrder.objects.create(name='fff', size=20, date=date(2007, 1, 1))
 
1206
>>> print_tree_details(MultiOrder.tree.all())
 
1207
2 - 1 0 1 2
 
1208
3 - 2 0 1 2
 
1209
1 - 3 0 1 2
 
1210
 
 
1211
>>> r4 = MultiOrder.objects.create(name='fff', size=20, date=date(2008, 1, 1))
 
1212
>>> print_tree_details(MultiOrder.tree.all())
 
1213
2 - 1 0 1 2
 
1214
3 - 2 0 1 2
 
1215
1 - 3 0 1 2
 
1216
4 - 4 0 1 2
 
1217
 
 
1218
>>> r5 = MultiOrder.objects.create(name='fff', size=20, date=date(2007, 1, 1))
 
1219
>>> print_tree_details(MultiOrder.tree.all())
 
1220
2 - 1 0 1 2
 
1221
3 - 2 0 1 2
 
1222
5 - 3 0 1 2
 
1223
1 - 4 0 1 2
 
1224
4 - 5 0 1 2
 
1225
 
 
1226
>>> r6 = MultiOrder.objects.create(name='aaa', size=999, date=date(2010, 1, 1))
 
1227
>>> print_tree_details(MultiOrder.tree.all())
 
1228
6 - 1 0 1 2
 
1229
2 - 2 0 1 2
 
1230
3 - 3 0 1 2
 
1231
5 - 4 0 1 2
 
1232
1 - 5 0 1 2
 
1233
4 - 6 0 1 2
 
1234
 
 
1235
# Child nodes
 
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))
 
1239
1 - 5 0 1 4
 
1240
7 1 5 1 2 3
 
1241
 
 
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))
 
1245
1 - 5 0 1 6
 
1246
7 1 5 1 2 3
 
1247
8 1 5 1 4 5
 
1248
 
 
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))
 
1252
1 - 5 0 1 8
 
1253
7 1 5 1 2 3
 
1254
9 1 5 1 4 5
 
1255
8 1 5 1 6 7
 
1256
 
 
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))
 
1260
1 - 5 0 1 10
 
1261
7 1 5 1 2 3
 
1262
9 1 5 1 4 5
 
1263
10 1 5 1 6 7
 
1264
8 1 5 1 8 9
 
1265
"""