Skip to main content

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's MP_Node
    • LTreeMPTTMixin — API compatible with django-mptt's MPTTModel
  • 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 ltree extension
  • 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 parent ForeignKey to self
  • An path LTreeField that stores the materialized path

Two PostgreSQL triggers maintain the paths:

  1. compute_path — On INSERT or UPDATE of parent_id, computes the node's path from its parent's path + its own PK
  2. update_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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_ltree_xtd-0.1.0.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_ltree_xtd-0.1.0-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

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

Hashes for django_ltree_xtd-0.1.0.tar.gz
Algorithm Hash digest
SHA256 71adfddb6d52804ed69b6a43f091ec2ff3a5899eed5a6814ef9ffaaf4c5376ee
MD5 833e1ea38a38d94d4bb688c89c2ca46f
BLAKE2b-256 2917e6e16a8eb8bd4f3361f2a1128fb29dc39da4a2c959bb0fe607e02ba5fef4

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_ltree_xtd-0.1.0.tar.gz:

Publisher: publish.yml on arthanson/django-ltree-xtd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_ltree_xtd-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_ltree_xtd-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 96ee39b8fdd0c36959af37e8dbaf63df9534dd8f5b16505323e30f4bd3f0afdf
MD5 5708b2e0a81b755c092e4197dbb10a5a
BLAKE2b-256 72e88918b466df0708555d0ec118b9ba3fd6b5dd89477e8d2000f17edeeaac99

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page