PostgreSQL ltree-based tree models for Django with trigger-maintained paths
Project description
django-ltree-xtd
PostgreSQL ltree-based tree models for Django with trigger-maintained paths.
Provides two abstract model mixins that use PostgreSQL's native ltree extension for efficient hierarchical data, with database triggers (via django-pgtrigger) to automatically maintain tree paths.
Features
- Native PostgreSQL ltree for fast hierarchical queries using GiST indexes
- Trigger-maintained paths — paths are computed and cascaded automatically by the database
- Two API flavors:
LTreeTreebeardMixin— API compatible with django-treebeard'sMP_NodeLTreeMPTTMixin— API compatible with django-mptt'sMPTTModel
- PK-based paths (e.g.,
1.42.103) — no slug collisions, no label length limits - No application-level path management — the database enforces integrity
Requirements
- Python 3.10+
- Django 4.2+
- PostgreSQL with the
ltreeextension - django-pgtrigger 4.11+
Installation
pip install django-ltree-xtd
Add to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"ltree",
# ...
]
Run migrations to create the ltree extension:
python manage.py migrate ltree
Quick Start
Using the Treebeard-compatible API
from django.db import models
from ltree.models import LTreeTreebeardMixin
class Category(LTreeTreebeardMixin):
name = models.CharField(max_length=255)
# Create tree
root = Category.add_root(name="Electronics")
laptops = root.add_child(name="Laptops")
phones = root.add_child(name="Phones")
gaming = laptops.add_child(name="Gaming Laptops")
# Navigate
root.get_children() # [laptops, phones]
root.get_descendants() # [laptops, phones, gaming]
gaming.get_ancestors() # [root, laptops]
gaming.get_root() # root
# Check relationships
gaming.is_descendant_of(root) # True
root.is_leaf() # False
gaming.is_leaf() # True
# Bulk operations
data = Category.dump_bulk()
Category.load_bulk(data)
Using the MPTT-compatible API
from django.db import models
from ltree.models import LTreeMPTTMixin
class Tag(LTreeMPTTMixin):
name = models.CharField(max_length=255)
# Create tree
root = Tag.objects.create(name="Root", parent=None)
child = Tag.objects.create(name="Child", parent=root)
grandchild = Tag.objects.create(name="Grandchild", parent=child)
# Navigate (MPTT-style)
grandchild.get_ancestors() # [root, child]
grandchild.get_ancestors(ascending=True) # [child, root]
root.get_descendants(include_self=True) # [root, child, grandchild]
root.get_family() # [root, child, grandchild]
root.get_leafnodes() # [grandchild]
grandchild.get_level() # 2
# Move nodes
grandchild.move_to(root, position="first-child")
# Boolean checks
root.is_root_node() # True
grandchild.is_leaf_node() # True
grandchild.is_child_node() # True
# Manager methods
Tag.objects.root_nodes()
Tag.objects.get_queryset_descendants(some_queryset)
Tag.objects.get_queryset_ancestors(some_queryset)
How It Works
Both mixins provide:
- A
parentForeignKey to self - An
pathLTreeField that stores the materialized path
Two PostgreSQL triggers maintain the paths:
compute_path— On INSERT or UPDATE ofparent_id, computes the node's path from its parent's path + its own PKupdate_descendants— After a path change, cascades the update to all descendants
This means moving a subtree is a single UPDATE that triggers automatic cascading — no application-level tree rebuilding needed.
License
MIT
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.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_ltree_xtd-0.1.0.tar.gz.
File metadata
- Download URL: django_ltree_xtd-0.1.0.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71adfddb6d52804ed69b6a43f091ec2ff3a5899eed5a6814ef9ffaaf4c5376ee
|
|
| MD5 |
833e1ea38a38d94d4bb688c89c2ca46f
|
|
| BLAKE2b-256 |
2917e6e16a8eb8bd4f3361f2a1128fb29dc39da4a2c959bb0fe607e02ba5fef4
|
Provenance
The following attestation bundles were made for django_ltree_xtd-0.1.0.tar.gz:
Publisher:
publish.yml on arthanson/django-ltree-xtd
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_ltree_xtd-0.1.0.tar.gz -
Subject digest:
71adfddb6d52804ed69b6a43f091ec2ff3a5899eed5a6814ef9ffaaf4c5376ee - Sigstore transparency entry: 1229831556
- Sigstore integration time:
-
Permalink:
arthanson/django-ltree-xtd@c421706baa4503a119b37d1af2f6af2639617ddd -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/arthanson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c421706baa4503a119b37d1af2f6af2639617ddd -
Trigger Event:
release
-
Statement type:
File details
Details for the file django_ltree_xtd-0.1.0-py3-none-any.whl.
File metadata
- Download URL: django_ltree_xtd-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96ee39b8fdd0c36959af37e8dbaf63df9534dd8f5b16505323e30f4bd3f0afdf
|
|
| MD5 |
5708b2e0a81b755c092e4197dbb10a5a
|
|
| BLAKE2b-256 |
72e88918b466df0708555d0ec118b9ba3fd6b5dd89477e8d2000f17edeeaac99
|
Provenance
The following attestation bundles were made for django_ltree_xtd-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on arthanson/django-ltree-xtd
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_ltree_xtd-0.1.0-py3-none-any.whl -
Subject digest:
96ee39b8fdd0c36959af37e8dbaf63df9534dd8f5b16505323e30f4bd3f0afdf - Sigstore transparency entry: 1229831613
- Sigstore integration time:
-
Permalink:
arthanson/django-ltree-xtd@c421706baa4503a119b37d1af2f6af2639617ddd -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/arthanson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c421706baa4503a119b37d1af2f6af2639617ddd -
Trigger Event:
release
-
Statement type: