django-treenode is probably the best abstract model / admin for your tree based stuff.
Project description
django-treenode
Probably the best abstract model / admin for your tree based stuff.
Features
Fast - get ancestors, children, descendants, parent, root, siblings, tree with no queries
Synced - in-memory model instances are automatically updated
Compatibility - you can easily add treenode to existing projects
No dependencies
Easy configuration - just extend the abstract model / model-admin
Admin integration - great tree visualization with optional accordion
Simple admin |
Accordion admin |
---|---|
Requirements
Python 2.7, 3.4, 3.5, 3.6, 3.7
Django 1.8, 1.9, 1.10, 1.11, 2.0, 2.1
Installation
Run pip install django-treenode
Add treenode to settings.INSTALLED_APPS
Make your model inherit from treenode.models.TreeNodeModel (described below)
Make your model-admin inherit from treenode.admin.TreeNodeModelAdmin (described below)
Run python manage.py makemigrations and python manage.py migrate
Configuration
models.py
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.
admin.py
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):
# if True an accordion will be used in the changelist view
# default value False
treenode_accordion = True
# use TreeNodeForm to automatically exclude invalid parent choices
form = TreeNodeForm
admin.site.register(Category, CategoryAdmin)
Usage
Methods/Properties:
Delete a node and all its descendants:
obj.delete()
Delete the whole tree for the current node class:
cls.delete_tree()
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 queryset:
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 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 queryset:
obj.get_descendants_queryset()
Get a n-dimensional dict representing the model tree:
obj.get_descendants_tree()
# or
obj.descendants_tree
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
Set the parent node:
obj.set_parent(parent_obj)
Get the node priority:
obj.get_priority()
# or
obj.priority
Set the node priority:
obj.set_priority(100)
Get the root node for the current node:
obj.get_root()
# or
obj.root
Get a list with all root nodes:
cls.get_roots()
# or
cls.roots
Get root nodes queryset:
cls.get_roots_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 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:
obj.is_first_child()
Return True if the current node is the last child:
obj.is_last_child()
Return True if the current node is leaf (it has not children):
obj.is_leaf()
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:
obj.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:
cls.update_tree()
License
Released under MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.