Skip to main content

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'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

Project details


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.

Supported by

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