Probably the best abstract model / admin for your tree based stuff.
ancestors
, children
, descendants
, parent
, root
, siblings
, tree
with no queriestreenode
to existing projectspip install django-treenode
treenode
to settings.INSTALLED_APPS
treenode.models.TreeNodeModel
(described below)treenode.admin.TreeNodeModelAdmin
(described below)python manage.py makemigrations
and python manage.py migrate
Make your model class inherit from treenode.models.TreeNodeModel
:
from django.db import models from treenode.models import TreeNodeModel class Category(TreeNodeModel): # the field used to display the model instance # default value 'pk' treenode_display_field = "name" name = models.CharField(max_length=50) class Meta(TreeNodeModel.Meta): verbose_name = "Category" verbose_name_plural = "Categories"
The TreeNodeModel
abstract class adds many fields (prefixed with tn_
to prevent direct access) and public methods to your models.
โ ๏ธ If you are extending a model that already has some fields, please ensure that your model existing fields names don't clash with TreeNodeModel
public methods/properties names.
Make your model-admin class inherit from treenode.admin.TreeNodeModelAdmin
.
from django.contrib import admin from treenode.admin import TreeNodeModelAdmin from treenode.forms import TreeNodeForm from .models import Category class CategoryAdmin(TreeNodeModelAdmin): # set the changelist display mode: 'accordion', 'breadcrumbs' or 'indentation' (default) # when changelist results are filtered by a querystring, # 'breadcrumbs' mode will be used (to preserve data display integrity) treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_ACCORDION # treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_BREADCRUMBS # treenode_display_mode = TreeNodeModelAdmin.TREENODE_DISPLAY_MODE_INDENTATION # use TreeNodeForm to automatically exclude invalid parent choices form = TreeNodeForm admin.site.register(Category, CategoryAdmin)
You can use a custom cache backend by adding a treenode
entry to settings.CACHES
, otherwise the default cache backend will be used.
CACHES = { "default": { "BACKEND": "django.core.cache.backends.filebased.FileBasedCache", "LOCATION": "...", }, "treenode": { "BACKEND": "django.core.cache.backends.locmem.LocMemCache", }, }
delete
delete_tree
get_ancestors
get_ancestors_count
get_ancestors_pks
get_ancestors_queryset
get_breadcrumbs
get_children
get_children_count
get_children_pks
get_children_queryset
get_depth
get_descendants
get_descendants_count
get_descendants_pks
get_descendants_queryset
get_descendants_tree
get_descendants_tree_display
get_first_child
get_index
get_last_child
get_level
get_order
get_parent
get_parent_pk
set_parent
get_priority
set_priority
get_root
get_root_pk
get_roots
get_roots_queryset
get_siblings
get_siblings_count
get_siblings_pks
get_siblings_queryset
get_tree
get_tree_display
is_ancestor_of
is_child_of
is_descendant_of
is_first_child
is_last_child
is_leaf
is_parent_of
is_root
is_root_of
is_sibling_of
update_tree
Delete a node if cascade=True
(default behaviour), children and descendants will be deleted too, otherwise children's parent will be set to None
(then children become roots):
Delete the whole tree for the current node class:
Get a list with all ancestors (ordered from root to parent):
obj.get_ancestors() # or obj.ancestors
Get the ancestors count:
obj.get_ancestors_count() # or obj.ancestors_count
Get the ancestors pks list:
obj.get_ancestors_pks() # or obj.ancestors_pks
Get the ancestors queryset (ordered from parent to root):
obj.get_ancestors_queryset()
Get the breadcrumbs to current node (included):
obj.get_breadcrumbs(attr=None) # or obj.breadcrumbs
Get a list containing all children:
obj.get_children() # or obj.children
Get the children count:
obj.get_children_count() # or obj.children_count
Get the children pks list:
obj.get_children_pks() # or obj.children_pks
Get the children queryset:
obj.get_children_queryset()
Get the node depth (how many levels of descendants):
obj.get_depth() # or obj.depth
Get a list containing all descendants:
obj.get_descendants() # or obj.descendants
Get the descendants count:
obj.get_descendants_count() # or obj.descendants_count
Get the descendants pks list:
obj.get_descendants_pks() # or obj.descendants_pks
Get the descendants queryset:
obj.get_descendants_queryset()
Get a n-dimensional dict
representing the model tree:
obj.get_descendants_tree() # or obj.descendants_tree
get_descendants_tree_display
Get a multiline string
representing the model tree:
obj.get_descendants_tree_display() # or obj.descendants_tree_display
Get the first child node:
obj.get_first_child() # or obj.first_child
Get the node index (index in node.parent.children list):
obj.get_index() # or obj.index
Get the last child node:
obj.get_last_child() # or obj.last_child
Get the node level (starting from 1):
obj.get_level() # or obj.level
Get the order value used for ordering:
obj.get_order() # or obj.order
Get the parent node:
obj.get_parent() # or obj.parent
Get the parent node pk:
obj.get_parent_pk() # or obj.parent_pk
Set the parent node:
obj.set_parent(parent_obj)
Get the node priority:
obj.get_priority() # or obj.priority
Set the node priority:
Get the root node for the current node:
obj.get_root() # or obj.root
Get the root node pk for the current node:
obj.get_root_pk() # or obj.root_pk
Get a list with all root nodes:
cls.get_roots() # or cls.roots
Get root nodes queryset:
Get a list with all the siblings:
obj.get_siblings() # or obj.siblings
Get the siblings count:
obj.get_siblings_count() # or obj.siblings_count
Get the siblings pks list:
obj.get_siblings_pks() # or obj.siblings_pks
Get the siblings queryset:
obj.get_siblings_queryset()
Get a n-dimensional dict
representing the model tree:
cls.get_tree() # or cls.tree
Get a multiline string
representing the model tree:
cls.get_tree_display() # or cls.tree_display
Return True
if the current node is ancestor of target_obj:
obj.is_ancestor_of(target_obj)
Return True
if the current node is child of target_obj:
obj.is_child_of(target_obj)
Return True
if the current node is descendant of target_obj:
obj.is_descendant_of(target_obj)
Return True
if the current node is the first child:
Return True
if the current node is the last child:
Return True
if the current node is leaf (it has not children):
Return True
if the current node is parent of target_obj:
obj.is_parent_of(target_obj)
Return True
if the current node is root:
Return True
if the current node is root of target_obj:
obj.is_root_of(target_obj)
Return True
if the current node is sibling of target_obj:
obj.is_sibling_of(target_obj)
Update tree manually, useful after bulk updates:
To perform bulk operations it is recommended to turn off signals, then triggering the tree update at the end:
from treenode.signals import no_signals with no_signals(): # execute custom bulk operations pass # trigger tree update only once YourModel.update_tree()Custom tree serialization
How can I serialize a tree using a custom data structure?
This has been discussed here.
# clone repository git clone https://github.com/fabiocaccamo/django-treenode.git && cd django-treenode # create virtualenv and activate it python -m venv venv && . venv/bin/activate # upgrade pip python -m pip install --upgrade pip # install requirements pip install -r requirements.txt -r requirements-test.txt # install pre-commit to run formatters and linters pre-commit install --install-hooks # run tests tox # or python runtests.py # or python -m django test --settings "tests.settings"
Released under MIT License.
django-admin-interface
- the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐ง โก
django-cache-cleaner
- clear the entire cache or individual caches easily using the admin panel or management command. ๐งนโจ
django-colorfield
- simple color field for models with a nice color-picker in the admin. ๐จ
django-extra-settings
- config and manage typed extra settings using just the django admin. โ๏ธ
django-maintenance-mode
- shows a 503 error page when maintenance-mode is on. ๐ง ๐ ๏ธ
django-redirects
- redirects with full control. โช๏ธ
python-benedict
- dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. ๐
python-codicefiscale
- encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐ฎ๐น ๐ณ
python-fontbro
- friendly font operations. ๐งข
python-fsutil
- file-system utilities for lazy devs. ๐งโโ๏ธ
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4