Directed Acyclic Graph implementation for Django & Postgresql
Project description
Django & PostgreSQL-based Directed Acyclic Graphs
Model directed acyclic graphs in Django without paying for the traversal one query at a time.
A lot of graph libraries walk a hierarchy level by level, firing a query for each generation. This one pushes the whole traversal down into PostgreSQL with recursive Common Table Expressions (CTEs), so reading every descendant of a node, every ancestor, or the path between two nodes is a single query regardless of how deep the graph runs.
The catch is portability. That speed comes from Postgres-specific SQL, so this library runs on PostgreSQL only. SQLite, MySQL, and the rest are not supported, and that is unlikely to change.
Is this the right package?
It is a good fit if you want to build and manipulate DAGs that live in your database: add and remove edges, walk ancestors and descendants, find paths, and run the usual DAG algorithms directly against your tables.
It is the wrong fit if you mainly want graph analysis or visualization. If your graph fits in memory and you just want to run algorithms over it, NetworkX or rustworkx will serve you better. When you do need them, the transforms extra hands your data straight to either one.
A quick taste
Define an edge model first, then the node model that connects through it:
from django.db import models
from django_postgresql_dag.models import node_factory, edge_factory
class Edge(edge_factory("Node")):
pass
class Node(node_factory(Edge)):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
Then wire up a graph and ask it questions:
root = Node.objects.create(name="root")
a = Node.objects.create(name="a")
b = Node.objects.create(name="b")
c = Node.objects.create(name="c")
root.add_child(a)
root.add_child(b)
a.add_child(c)
b.add_child(c) # c has two parents; that is what makes this a DAG and not a tree
root.descendants() # every node below root, one query deep or fifty deep
c.ancestors() # everything above c
root.path(c) # a route from root down to c
c.is_leaf() # True
Adding an edge that would close a loop raises an error by default, so the graph stays acyclic without you policing it. You can relax that (and the duplicate/redundant-edge checks) per model if you have a reason to.
Install
pip install django-postgresql-dag
For NetworkX, rustworkx, and JSON export:
pip install django-postgresql-dag[transforms]
Configuration
Graph traversals stop at a maximum depth so a runaway query cannot wander forever. The default is 20. To change it project-wide:
# settings.py
DJANGO_POSTGRESQL_DAG_MAX_DEPTH = 50
You can still override it on any individual call with max_depth=N.
What you can do with a node
Traversal and paths: ancestors(), descendants(), clan(), path(target), connected_graph(), plus the matching edge queries (ancestors_edges(), descendants_edges(), clan_edges()).
Structure and relationships: roots(), leaves(), siblings(), partners(), ancestors_tree(), descendants_tree().
Mutations: add_child(), remove_child(), add_parent(), remove_parent().
Predicates: is_root(), is_leaf(), is_island(), is_ancestor_of(), is_descendant_of().
Heavier algorithms: depth annotation, topological sort, all-paths enumeration, lowest common ancestor, weighted shortest path, critical (longest) path, transitive reduction, and graph hashing (Weisfeiler-Lehman, via NetworkX).
You can also narrow the part of the graph a traversal searches with disallow_nodes, allow_nodes, disallow_edges, allow_edges, and limiting_edges_set_fk (with edge_type as a shorthand). Manager methods connected_components() and graph_stats() work across the whole graph.
The node reference and edge reference cover every method in detail.
Documentation
Quickstart walks through a full example. The Tutorial explains why the pieces fit together the way they do. Everything else lives in the full documentation.
Roadmap
The issue tracker holds the running checklists of where this is headed.
Credits
Earlier projects and writing this one borrows from:
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_postgresql_dag-2026.7.1.tar.gz.
File metadata
- Download URL: django_postgresql_dag-2026.7.1.tar.gz
- Upload date:
- Size: 68.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8cb26cb856d9827ef0decd35d19ab6c15d1c2ea7dde5205fd3018939f0e7db4
|
|
| MD5 |
4b8b3f477bb5ff7e553441e90124ba75
|
|
| BLAKE2b-256 |
d8274fded76e7ab4554c50652a1076539de0ad65abd574eb964e59aadf0000e1
|
File details
Details for the file django_postgresql_dag-2026.7.1-py3-none-any.whl.
File metadata
- Download URL: django_postgresql_dag-2026.7.1-py3-none-any.whl
- Upload date:
- Size: 37.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f40f07a25626ee3a099735410268ea276120094fe34d7a435620f604c7e410b8
|
|
| MD5 |
1d2885de12b8ceae591f79bd52c3bbcc
|
|
| BLAKE2b-256 |
57374247dad268a1ef3c84956d2c46add790a18d22221e296027c2f38d593286
|