Skip to main content

Directed Acyclic Graph implementation for Django & Postgresql

Project description

Django & PostgreSQL-based Directed Acyclic Graphs

PyPI Python versions Django versions Documentation License: MIT

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:

  1. This blog post on recursive CTEs and topological sort in Postgres
  2. django-dag
  3. django-dag-postgresql
  4. django-treebeard-dag

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_postgresql_dag-2026.7.1.tar.gz (68.8 kB view details)

Uploaded Source

Built Distribution

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

django_postgresql_dag-2026.7.1-py3-none-any.whl (37.6 kB view details)

Uploaded Python 3

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

Hashes for django_postgresql_dag-2026.7.1.tar.gz
Algorithm Hash digest
SHA256 c8cb26cb856d9827ef0decd35d19ab6c15d1c2ea7dde5205fd3018939f0e7db4
MD5 4b8b3f477bb5ff7e553441e90124ba75
BLAKE2b-256 d8274fded76e7ab4554c50652a1076539de0ad65abd574eb964e59aadf0000e1

See more details on using hashes here.

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

Hashes for django_postgresql_dag-2026.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f40f07a25626ee3a099735410268ea276120094fe34d7a435620f604c7e410b8
MD5 1d2885de12b8ceae591f79bd52c3bbcc
BLAKE2b-256 57374247dad268a1ef3c84956d2c46add790a18d22221e296027c2f38d593286

See more details on using hashes here.

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