django-fast-treenode 2.0.10__py3-none-any.whl → 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {django_fast_treenode-2.0.10.dist-info → django_fast_treenode-2.1.0.dist-info}/LICENSE +2 -2
  2. django_fast_treenode-2.1.0.dist-info/METADATA +161 -0
  3. django_fast_treenode-2.1.0.dist-info/RECORD +75 -0
  4. {django_fast_treenode-2.0.10.dist-info → django_fast_treenode-2.1.0.dist-info}/WHEEL +1 -1
  5. treenode/admin/__init__.py +9 -0
  6. treenode/admin/admin.py +295 -0
  7. treenode/admin/changelist.py +65 -0
  8. treenode/admin/mixins.py +302 -0
  9. treenode/apps.py +12 -1
  10. treenode/cache.py +2 -2
  11. treenode/docs/.gitignore +0 -0
  12. treenode/docs/about.md +36 -0
  13. treenode/docs/admin.md +104 -0
  14. treenode/docs/api.md +739 -0
  15. treenode/docs/cache.md +187 -0
  16. treenode/docs/import_export.md +35 -0
  17. treenode/docs/index.md +30 -0
  18. treenode/docs/installation.md +74 -0
  19. treenode/docs/migration.md +145 -0
  20. treenode/docs/models.md +128 -0
  21. treenode/docs/roadmap.md +45 -0
  22. treenode/forms.py +33 -22
  23. treenode/managers/__init__.py +21 -0
  24. treenode/managers/adjacency.py +203 -0
  25. treenode/managers/closure.py +278 -0
  26. treenode/models/__init__.py +2 -1
  27. treenode/models/adjacency.py +343 -0
  28. treenode/models/classproperty.py +3 -0
  29. treenode/models/closure.py +39 -65
  30. treenode/models/factory.py +12 -2
  31. treenode/models/mixins/__init__.py +23 -0
  32. treenode/models/mixins/ancestors.py +65 -0
  33. treenode/models/mixins/children.py +81 -0
  34. treenode/models/mixins/descendants.py +66 -0
  35. treenode/models/mixins/family.py +63 -0
  36. treenode/models/mixins/logical.py +68 -0
  37. treenode/models/mixins/node.py +210 -0
  38. treenode/models/mixins/properties.py +156 -0
  39. treenode/models/mixins/roots.py +96 -0
  40. treenode/models/mixins/siblings.py +99 -0
  41. treenode/models/mixins/tree.py +344 -0
  42. treenode/signals.py +26 -0
  43. treenode/static/treenode/css/tree_widget.css +201 -31
  44. treenode/static/treenode/css/treenode_admin.css +48 -41
  45. treenode/static/treenode/js/tree_widget.js +269 -131
  46. treenode/static/treenode/js/treenode_admin.js +131 -171
  47. treenode/templates/admin/tree_node_changelist.html +6 -0
  48. treenode/templates/admin/tree_node_import.html +27 -9
  49. treenode/templates/admin/tree_node_import_report.html +32 -0
  50. treenode/templates/admin/treenode_ajax_rows.html +7 -0
  51. treenode/tests/tests.py +488 -0
  52. treenode/urls.py +10 -6
  53. treenode/utils/__init__.py +2 -0
  54. treenode/utils/aid.py +46 -0
  55. treenode/utils/base16.py +38 -0
  56. treenode/utils/base36.py +3 -1
  57. treenode/utils/db.py +116 -0
  58. treenode/utils/exporter.py +63 -36
  59. treenode/utils/importer.py +168 -161
  60. treenode/utils/radix.py +61 -0
  61. treenode/version.py +2 -2
  62. treenode/views.py +119 -38
  63. treenode/widgets.py +104 -40
  64. django_fast_treenode-2.0.10.dist-info/METADATA +0 -698
  65. django_fast_treenode-2.0.10.dist-info/RECORD +0 -41
  66. treenode/admin.py +0 -396
  67. treenode/docs/Documentation +0 -664
  68. treenode/managers.py +0 -281
  69. treenode/models/proxy.py +0 -650
  70. {django_fast_treenode-2.0.10.dist-info → django_fast_treenode-2.1.0.dist-info}/top_level.txt +0 -0
@@ -1,664 +0,0 @@
1
- # Django-fast-treenode
2
- __Combination of Adjacency List and Closure Table__
3
-
4
- ## Functions
5
- Application for supporting tree (hierarchical) data structure in Django projects
6
- * fast: the fastest of the two methods is used to process requests, combining the advantages of an **Adjacency Table** and a **Closure Table**,
7
- * even faster: the main resource-intensive operations are **cached**; **bulk operations** are used for inserts and changes,
8
- * synchronized: model instances in memory are automatically updated,
9
- * compatibility: you can easily add a tree node to existing projects using TreeNode without changing the code,
10
- * no dependencies,
11
- * easy setup: just extend the abstract model/model-admin,
12
- * admin integration: visualization options (accordion, breadcrumbs or padding),
13
- * widget: Built-in Select2-to-Tree extends Select2 to support arbitrary nesting levels.
14
-
15
- ## Debut idea
16
- This is a modification of the reusable [django-treenode](https://github.com/fabiocaccamo/django-treenode) application developed by [Fabio Caccamo](https://github.com/fabiocaccamo).
17
- The original application has significant advantages over other analogues, and indeed, is one of the best implementations of support for hierarchical structures for Django.
18
-
19
- Fabio's idea was to use the Adjacency List method to store the data tree. The most probable and time-consuming requests are calculated in advance and stored in the database. Also, most requests are cached. As a result, query processing is carried out in one call to the database or without it at all.
20
-
21
- However, this application has a number of undeniable shortcomings:
22
- * the selected pre-calculations scheme entails high costs for adding a new element;
23
- * inserting new elements uses signals, which leads to failures when using bulk-operations;
24
- * the problem of ordering elements by priority inside the parent node has not been resolved.
25
-
26
- My idea was to solve these problems by combining the adjacency list with the Closure Table. Main advantages:
27
- * the Closure Model is generated automatically;
28
- * maintained compatibility with the original package at the level of documented functions;
29
- * most requests are satisfied in one call to the database;
30
- * inserting a new element takes two calls to the database without signals usage;
31
- * bulk-operations are supported;
32
- * the cost of creating a new dependency is reduced many times;
33
- * useful functionality added for some methods (e.g. the `include_self=False` and `depth` parameters has been added to functions that return lists/querysets);
34
- * additionally, the package includes a tree view widget for the `tn_parent` field in the change form.
35
-
36
- Of course, at large levels of nesting, the use of the Closure Table leads to an increase in resource costs. But at the same time, the combined scheme still generally outperforms the original application in terms of performance.
37
-
38
- ## Theory
39
- You can get a basic understanding of what is a Closure Table from:
40
- * [presentation](https://www.slideshare.net/billkarwin/models-for-hierarchical-data) by Bill Karwin;
41
- * [article](https://dirtsimple.org/2010/11/simplest-way-to-do-tree-based-queries.html) by blogger Dirt Simple;
42
- * [article](https://towardsdatascience.com/closure-table-pattern-to-model-hierarchies-in-nosql-c1be6a87e05b) by Andriy Zabavskyy.
43
-
44
- You can easily find additional information on your own on the Internet.
45
-
46
- ## Quick start
47
- 1. Run ```pip install django-fast-treenode```
48
- 2. Add ```treenode``` to ```settings.INSTALLED_APPS```
49
- 3. Make your model inherit from ```treenode.models.TreeNodeModel``` (described below)
50
- 4. Make your model-admin inherit from ```treenode.admin.TreeNodeModelAdmin``` (described below)
51
- 5. Run python manage.py makemigrations and ```python manage.py migrate```
52
-
53
- For more information on migrating from the **django-treenode** package and upgrading to version 2.0, see [below](#migration-guide).
54
-
55
- ## Configuration
56
- ### `models.py`
57
- Make your model class inherit from `treenode.models.TreeNodeModel`:
58
-
59
- ```python
60
- from django.db import models
61
- from treenode.models import TreeNodeModel
62
-
63
-
64
- class Category(TreeNodeModel):
65
-
66
- # the field used to display the model instance
67
- # default value 'pk'
68
- treenode_display_field = "name"
69
-
70
- name = models.CharField(max_length=50)
71
-
72
- class Meta(TreeNodeModel.Meta):
73
- verbose_name = "Category"
74
- verbose_name_plural = "Categories"
75
- ```
76
-
77
- The `TreeNodeModel` abstract class adds many fields (prefixed with `tn_` to prevent direct access) and public methods to your models.
78
-
79
- ### `admin.py`
80
- Make your model-admin class inherit from `treenode.admin.TreeNodeModelAdmin`.
81
-
82
- ```python
83
- from django.contrib import admin
84
-
85
- from treenode.admin import TreeNodeModelAdmin
86
- from treenode.forms import TreeNodeForm
87
-
88
- from .models import Category
89
-
90
-
91
- class CategoryAdmin(TreeNodeModelAdmin):
92
-
93
- # set the changelist display mode: 'accordion', 'breadcrumbs' or 'indentation' (default)
94
- # when changelist results are filtered by a querystring,
95
- # 'breadcrumbs' mode will be used (to preserve data display integrity)
96
- treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_ACCORDION
97
- # treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_BREADCRUMBS
98
- # treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_INDENTATION
99
-
100
- # use TreeNodeForm to automatically exclude invalid parent choices
101
- form = TreeNodeForm
102
-
103
- admin.site.register(Category, CategoryAdmin)
104
- ```
105
-
106
- ---
107
-
108
- ### `settings.py`
109
- You can use a custom cache backend by adding a `treenode` entry to `settings.CACHES`, otherwise the default cache backend will be used.
110
-
111
- ```python
112
- CACHES = {
113
- "default": {
114
- "BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
115
- "LOCATION": "...",
116
- },
117
- "treenode": {
118
- "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
119
- "KEY_PREFIX": "", # This is important!
120
- "VERSION": None, # This is important!
121
- },
122
- }
123
- ```
124
- ### `forms.py`
125
-
126
- ```
127
- class YoursForm(TreeNodeForm):
128
- # Your code is here
129
- ```
130
-
131
- ## Updating to django-fast-treenode 2.X
132
- ### Overview
133
- If you are upgrading from a previous version, you need to follow these steps to ensure compatibility and proper functionality.
134
-
135
- ### Update Process
136
- 1. **Upgrade the package**
137
- Run the following command to install the latest version:
138
-
139
- ```bash
140
- pip install --upgrade django-fast-treenode
141
- ```
142
-
143
- 2. **Apply database migrations**
144
- After upgrading, you need to apply the necessary database migrations:
145
-
146
- ```bash
147
- python manage.py makemigrations
148
- python manage.py migrate
149
- ```
150
-
151
- 3. **Restart the application**
152
- Finally, restart your Django application to apply all changes:
153
-
154
- ```bash
155
- python manage.py runserver
156
- ```
157
-
158
- **Important Notes**: Failing to apply migrations (`migrate`) after upgrading may lead to errors when interacting with tree nodes.
159
-
160
- By following these steps, you will ensure a smooth transition to the latest version of django-fast-treenode without data inconsistencies.
161
-
162
-
163
- ## Usage
164
- ### Methods/Properties
165
-
166
- - [`delete`](#delete)
167
- - [`delete_tree`](#delete_tree)
168
- - [`get_ancestors`](#get_ancestors)
169
- - [`get_ancestors_count`](#get_ancestors_count)
170
- - [`get_ancestors_pks`](#get_ancestors_pks)
171
- - [`get_ancestors_queryset`](#get_ancestors_queryset)
172
- - [`get_breadcrumbs`](#get_breadcrumbs)
173
- - [`get_children`](#get_children)
174
- - [`get_children_count`](#get_children_count)
175
- - [`get_children_pks`](#get_children_pks)
176
- - [`get_children_queryset`](#get_children_queryset)
177
- - [`get_depth`](#get_depth)
178
- - [`get_descendants`](#get_descendants)
179
- - [`get_descendants_count`](#get_descendants_count)
180
- - [`get_descendants_pks`](#get_descendants_pks)
181
- - [`get_descendants_queryset`](#get_descendants_queryset)
182
- - [`get_descendants_tree`](#get_descendants_tree)
183
- - [`get_descendants_tree_display`](#get_descendants_tree_display)
184
- - [`get_first_child`](#get_first_child)
185
- - [`get_index`](#get_index)
186
- - [`get_last_child`](#get_last_child)
187
- - [`get_level`](#get_level)
188
- - [`get_order`](#get_order)
189
- - [`get_parent`](#get_parent)
190
- - [`get_parent_pk`](#get_parent_pk)
191
- - [`set_parent`](#set_parent)
192
- - [`get_path`](#get_path)
193
- - [`get_priority`](#get_priority)
194
- - [`set_priority`](#set_priority)
195
- - [`get_root`](#get_root)
196
- - [`get_root_pk`](#get_root_pk)
197
- - [`get_roots`](#get_roots)
198
- - [`get_roots_queryset`](#get_roots_queryset)
199
- - [`get_siblings`](#get_siblings)
200
- - [`get_siblings_count`](#get_siblings_count)
201
- - [`get_siblings_pks`](#get_siblings_pks)
202
- - [`get_siblings_queryset`](#get_siblings_queryset)
203
- - [`get_tree`](#get_tree)
204
- - [`get_tree_display`](#get_tree_display)
205
- - [`is_ancestor_of`](#is_ancestor_of)
206
- - [`is_child_of`](#is_child_of)
207
- - [`is_descendant_of`](#is_descendant_of)
208
- - [`is_first_child`](#is_first_child)
209
- - [`is_last_child`](#is_last_child)
210
- - [`is_leaf`](#is_leaf)
211
- - [`is_parent_of`](#is_parent_of)
212
- - [`is_root`](#is_root)
213
- - [`is_root_of`](#is_root_of)
214
- - [`is_sibling_of`](#is_sibling_of)
215
- - [`update_tree`](#update_tree)
216
-
217
- #### `delete`
218
- **Delete a node** provides two deletion strategies:
219
- - **Cascade Delete (`cascade=True`)**: Removes the node along with all its descendants.
220
- - **Reparenting (`cascade=False`)**: Moves the children of the deleted node up one level in the hierarchy before removing the node itself.
221
-
222
- ```python
223
- node.delete(cascade=True) # Deletes node and all its descendants
224
- node.delete(cascade=False) # Moves children up and then deletes the node
225
- ```
226
- This ensures greater flexibility in managing tree structures while preventing orphaned nodes.
227
-
228
- ---
229
-
230
- #### `delete_tree`
231
- **Delete the whole tree** for the current node class:
232
- ```python
233
- cls.delete_tree()
234
- ```
235
-
236
- #### `get_ancestors`
237
- Get a **list with all ancestors** (ordered from root to parent):
238
- ```python
239
- obj.get_ancestors(include_self=True, depth=None)
240
- # or
241
- obj.ancestors
242
- ```
243
-
244
- #### `get_ancestors_count`
245
- Get the **ancestors count**:
246
- ```python
247
- obj.get_ancestors_count(include_self=True, depth=None)
248
- # or
249
- obj.ancestors_count
250
- ```
251
-
252
- #### `get_ancestors_pks`
253
- Get the **ancestors pks** list:
254
- ```python
255
- obj.get_ancestors_pks(include_self=True, depth=None)
256
- # or
257
- obj.ancestors_pks
258
- ```
259
-
260
- #### `get_ancestors_queryset`
261
- Get the **ancestors queryset** (ordered from parent to root):
262
- ```python
263
- obj.get_ancestors_queryset(include_self=True, depth=None)
264
- ```
265
-
266
- #### `get_breadcrumbs`
267
- Get the **breadcrumbs** to current node (included):
268
- ```python
269
- obj.get_breadcrumbs(attr=None)
270
- # or
271
- obj.breadcrumbs
272
- ```
273
-
274
- #### `get_children`
275
- Get a **list containing all children**:
276
- ```python
277
- obj.get_children()
278
- # or
279
- obj.children
280
- ```
281
-
282
- #### `get_children_count`
283
- Get the **children count**:
284
- ```python
285
- obj.get_children_count()
286
- # or
287
- obj.children_count
288
- ```
289
-
290
- #### `get_children_pks`
291
- Get the **children pks** list:
292
- ```python
293
- obj.get_children_pks()
294
- # or
295
- obj.children_pks
296
- ```
297
-
298
- #### `get_children_queryset`
299
- Get the **children queryset**:
300
- ```python
301
- obj.get_children_queryset()
302
- ```
303
-
304
- #### `get_depth`
305
- Get the **node depth** (how many levels of descendants):
306
- ```python
307
- obj.get_depth()
308
- # or
309
- obj.depth
310
- ```
311
-
312
- #### `get_descendants`
313
- Get a **list containing all descendants**:
314
- ```python
315
- obj.get_descendants(include_self=False, depth=None)
316
- # or
317
- obj.descendants
318
- ```
319
-
320
- #### `get_descendants_count`
321
- Get the **descendants count**:
322
- ```python
323
- obj.get_descendants_count(include_self=False, depth=None)
324
- # or
325
- obj.descendants_count
326
- ```
327
-
328
- #### `get_descendants_pks`
329
- Get the **descendants pks** list:
330
- ```python
331
- obj.get_descendants_pks(include_self=False, depth=None)
332
- # or
333
- obj.descendants_pks
334
- ```
335
-
336
- #### `get_descendants_queryset`
337
- Get the **descendants queryset**:
338
- ```python
339
- obj.get_descendants_queryset(include_self=False, depth=None)
340
- ```
341
-
342
- #### `get_descendants_tree`
343
- Get a **n-dimensional** `dict` representing the **model tree**:
344
- ```python
345
- obj.get_descendants_tree()
346
- # or
347
- obj.descendants_tree
348
- ```
349
-
350
- **Important**: In future projects, avoid using `get_descendants_tree()`. It will be removed in the next version.
351
-
352
- #### `get_descendants_tree_display`
353
- Get a **multiline** `string` representing the **model tree**:
354
- ```python
355
- obj.get_descendants_tree_display(include_self=False, depth=None)
356
- # or
357
- obj.descendants_tree_display
358
- ```
359
-
360
- **Important**: In future projects, avoid using `get_descendants_tree_display()`. It will be removed in the next version.
361
-
362
- #### `get_first_child`
363
- Get the **first child node**:
364
- ```python
365
- obj.get_first_child()
366
- # or
367
- obj.first_child
368
- ```
369
-
370
- #### `get_index`
371
- Get the **node index** (index in node.parent.children list):
372
- ```python
373
- obj.get_index()
374
- # or
375
- obj.index
376
- ```
377
-
378
- #### `get_last_child`
379
- Get the **last child node**:
380
- ```python
381
- obj.get_last_child()
382
- # or
383
- obj.last_child
384
- ```
385
-
386
- #### `get_level`
387
- Get the **node level** (starting from 1):
388
- ```python
389
- obj.get_level()
390
- # or
391
- obj.level
392
- ```
393
-
394
- #### `get_order`
395
- Get the **order value** used for ordering:
396
- ```python
397
- obj.get_order()
398
- # or
399
- obj.order
400
- ```
401
-
402
- #### `get_parent`
403
- Get the **parent node**:
404
- ```python
405
- obj.get_parent()
406
- # or
407
- obj.parent
408
- ```
409
-
410
- #### `get_parent_pk`
411
- Get the **parent node pk**:
412
- ```python
413
- obj.get_parent_pk()
414
- # or
415
- obj.parent_pk
416
- ```
417
-
418
- #### `set_parent`
419
- Set the **parent node**:
420
- ```python
421
- obj.set_parent(parent_obj)
422
- ```
423
-
424
- #### `get_priority`
425
- Get the **node priority**:
426
- ```python
427
- obj.get_priority()
428
- # or
429
- obj.priority
430
- ```
431
- #### `get_path`
432
- Added the function of decorating a **materialized path**. The path is formed according to the value of the `tn_priority` field.
433
- ```python
434
- cls.get_path(prefix='', suffix='', delimiter='.', format_str='')
435
- ```
436
-
437
- #### `set_priority`
438
- Set the **node priority**:
439
- ```python
440
- obj.set_priority(100)
441
- ```
442
-
443
- #### `get_root`
444
- Get the **root node** for the current node:
445
- ```python
446
- obj.get_root()
447
- # or
448
- obj.root
449
- ```
450
-
451
- #### `get_root_pk`
452
- Get the **root node pk** for the current node:
453
- ```python
454
- obj.get_root_pk()
455
- # or
456
- obj.root_pk
457
- ```
458
-
459
- #### `get_roots`
460
- Get a **list with all root nodes**:
461
- ```python
462
- cls.get_roots()
463
- # or
464
- cls.roots
465
- ```
466
-
467
- #### `get_roots_queryset`
468
- Get **root nodes queryset**:
469
- ```python
470
- cls.get_roots_queryset()
471
- ```
472
-
473
- #### `get_siblings`
474
- Get a **list with all the siblings**:
475
- ```python
476
- obj.get_siblings()
477
- # or
478
- obj.siblings
479
- ```
480
-
481
- #### `get_siblings_count`
482
- Get the **siblings count**:
483
- ```python
484
- obj.get_siblings_count()
485
- # or
486
- obj.siblings_count
487
- ```
488
-
489
- #### `get_siblings_pks`
490
- Get the **siblings pks** list:
491
- ```python
492
- obj.get_siblings_pks()
493
- # or
494
- obj.siblings_pks
495
- ```
496
-
497
- #### `get_siblings_queryset`
498
- Get the **siblings queryset**:
499
- ```python
500
- obj.get_siblings_queryset()
501
- ```
502
-
503
- #### `get_tree`
504
- Returns an **n-dimensional dictionary** representing the model tree. Each node
505
- contains a "children"=[] key with a list of nested dictionaries of child nodes.:
506
- ```python
507
- cls.get_tree(instance=None)
508
- # or
509
- cls.tree
510
- ```
511
-
512
- #### `get_tree_display`
513
- Get a **multiline** `string` representing the **model tree**:
514
- ```python
515
- cls.get_tree_display()
516
- # or
517
- cls.tree_display
518
- ```
519
-
520
- #### `is_ancestor_of`
521
- Return `True` if the current node **is ancestor** of target_obj:
522
- ```python
523
- obj.is_ancestor_of(target_obj)
524
- ```
525
-
526
- #### `is_child_of`
527
- Return `True` if the current node **is child** of target_obj:
528
- ```python
529
- obj.is_child_of(target_obj)
530
- ```
531
-
532
- #### `is_descendant_of`
533
- Return `True` if the current node **is descendant** of target_obj:
534
- ```python
535
- obj.is_descendant_of(target_obj)
536
- ```
537
-
538
- #### `is_first_child`
539
- Return `True` if the current node is the **first child**:
540
- ```python
541
- obj.is_first_child()
542
- ```
543
-
544
- #### `is_last_child`
545
- Return `True` if the current node is the **last child**:
546
- ```python
547
- obj.is_last_child()
548
- ```
549
-
550
- #### `is_leaf`
551
- Return `True` if the current node is **leaf** (it has not children):
552
- ```python
553
- obj.is_leaf()
554
- ```
555
-
556
- #### `is_parent_of`
557
- Return `True` if the current node **is parent** of target_obj:
558
- ```python
559
- obj.is_parent_of(target_obj)
560
- ```
561
-
562
- #### `is_root`
563
- Return `True` if the current node **is root**:
564
- ```python
565
- obj.is_root()
566
- ```
567
-
568
- #### `is_root_of`
569
- Return `True` if the current node **is root** of target_obj:
570
- ```python
571
- obj.is_root_of(target_obj)
572
- ```
573
-
574
- #### `is_sibling_of`
575
- Return `True` if the current node **is sibling** of target_obj:
576
- ```python
577
- obj.is_sibling_of(target_obj)
578
- ```
579
-
580
- #### `update_tree`
581
- **Update tree** manually, useful after **bulk updates**:
582
- ```python
583
- cls.update_tree()
584
- ```
585
- ## **Cache Management**
586
- ### **Overview**
587
- In v2.0, the caching mechanism has been improved to prevent excessive memory usage when multiple models inherit from `TreeNode`. The new system introduces **FIFO (First-In-First-Out) cache eviction**, with plans to test and integrate more advanced algorithms in future releases.
588
-
589
- ### **Key Features**
590
- **Global Cache Limit**: The setting `TREENODE_CACHE_LIMIT` defines the maximum cache size (in MB) for all models inheriting from `TreeNode`. Default is **100MB** if not explicitly set in `settings.py`.
591
- **settings.py**
592
- ``` python
593
- TREENODE_CACHE_LIMIT = 100
594
- ```
595
- **Automatic Management**: In most cases, users don’t need to manually manage cache operations.
596
- **Manual Cache Clearing**:
597
- - **Clear cache for a single model**: Use `clear_cache()` at the model level:
598
- ```python
599
- MyTreeNodeModel.clear_cache()
600
- ```
601
- - **Clear cache for all models**: Use the global `treenode_cache.clear()` method:
602
- ```python
603
- from treenode.cache import treenode_cache
604
- treenode_cache.clear()
605
- ```
606
-
607
- ## **Export and Import Functionality**
608
- ### **Overview**
609
- TreeNode v2.0 includes **built-in export and import features** for easier data migration. Supported Formats: `csv`, `json`, `xlsx`, `yaml`, `tsv`
610
- ### Installation for Import/Export Features
611
- By default, import/export functionality is **not included** to keep the package lightweight. If you need these features, install the package with:
612
- ```bash
613
- pip install django-fast-treenode[import_export]
614
- ```
615
- Once installed, **import/export buttons will appear** in the Django admin interface.
616
- ### **Important Considerations**
617
- Exporting objects with M2M fields may lead to serialization issues. Some formats (e.g., CSV) do not natively support many-to-many relationships. If you encounter errors, consider exporting data in `json` or `yaml` format, which better handle nested structures.
618
-
619
- ## Migration Guide
620
- #### Switching from `django-treenode`
621
- The migration process from `django-treenode` is fully automated. No manual steps are required. Upon upgrading, the necessary data structures will be checked and updated automatically. In exceptional cases, you can call the update code `cls.update_tree()` manually.
622
-
623
-
624
- #### Upgrading to `django-fast-treenode` 2.0
625
- To upgrade to version 2.0, simply run:
626
- ```bash
627
- pip install --upgrade django-fast-treenode
628
- ```
629
- or
630
- ```bash
631
- pip install django-fast-treenode[import_export]
632
- ```
633
- After upgrading, ensure that your database schema is up to date by running:
634
- ```bash
635
- python manage.py makemigrations
636
- python manage.py migrate
637
- ```
638
- This will apply any necessary database changes automatically.
639
-
640
- ## To do
641
- These improvements aim to enhance usability, performance, and maintainability for all users of `django-fast-treenode`:
642
- * **Cache Algorithm Optimization**: Testing and integrating more advanced cache eviction strategies.
643
- * **Drag-and-Drop UI Enhancements**: Adding intuitive drag-and-drop functionality for tree node management.
644
- * to be happy, to don't worry, until die.
645
-
646
- Your wishes, objections, comments are welcome.
647
-
648
-
649
- # Django-fast-treenode
650
- ## License
651
- Released under [MIT License](https://github.com/TimurKady/django-fast-treenode/blob/main/LICENSE).
652
-
653
- ## Cautions
654
- **Warning**: Do not access the tree node fields directly! Most of *django-treenode* model fields have been removed as unnecessary. Now only `tn_parent` and `tn_priority` are supported and will be kept in the future.
655
-
656
- **Risks of Direct Field Access:**
657
- - **Database Integrity Issues**: Directly modifying fields may break tree integrity, causing inconsistent parent-child relationships.
658
- - **Loss of Cached Data**: The caching system relies on controlled updates. Bypassing methods like `set_parent()` or `update_tree()` may lead to outdated or incorrect data.
659
- - **Unsupported Behavior**: Future versions may change field structures or remove unnecessary fields. Relying on them directly risks breaking compatibility.
660
-
661
- Instead, always use the **documented methods** described above or refer to the [original application documentation](https://github.com/fabiocaccamo/django-treenode).
662
-
663
- ## Credits
664
- This software contains, uses, and includes, in a modified form, [django-treenode](https://github.com/fabiocaccamo/django-treenode) by [Fabio Caccamo](https://github.com/fabiocaccamo). Special thanks to [Mathieu Leplatre](https://blog.mathieu-leplatre.info/pages/about.html) for the advice used in writing this application.