Top-down role-based access control for Django
Project description
django-topdownrbac
A Django library that implements hierarchical, top-down role-based access control (RBAC) with automatic permission propagation through object trees.
If you manage resources organized in a hierarchy (organizations, teams, projects, ...) and need a user with a role on a parent to automatically have that role on all descendants, this library handles it for you.
Why this exists
Django's built-in permission system is flat: you grant permissions globally or per object, but there is no concept of hierarchy or propagation. No existing third-party package supports scoping permissions to specific object instances within a tree and propagating them downward.
django-topdownrbac fills that gap. Permissions are materialized into a dedicated table (UserPermission) for O(1) lookups at query time — no tree traversal or recursive joins needed. All changes to roles, bindings, group membership, or hierarchy automatically cascade to keep this table in sync.
Trade-off: storage vs. speed. Materialization means every user × permission × object combination is stored as a row. This makes permission checks and queryset filtering very fast, but the UserPermission table grows proportionally to the number of users, roles, and objects in your hierarchy. For small-to-medium projects this is negligible; for large-scale deployments with deep hierarchies, many roles, and thousands of users, monitor table size and plan your database capacity accordingly.
Key concepts
| Concept | Model | Description |
|---|---|---|
| Subject | UserSubject, UserGroupSubject |
A user or group of users. UserSubject extends Django's AbstractUser. |
| Restricted Object | RestrictedObject |
Any object you want to protect. Organized as a tree (parent/children) using django-treebeard's Materialized Path. |
| Role | Role |
A named collection of Django permissions. Can be marked immutable or externally provisioned (via YAML). |
| Role Binding | RoleBinding |
Links a subject to a role on a specific restricted object. The propagate flag controls whether permissions apply to all descendants. |
| User Permission | UserPermission |
A materialized row: one user, one permission, one object. This is the table queried at check time. |
How it works
- Create a
RoleBindinglinking a subject + role + restricted object (optionally withpropagate=True). - The library automatically bulk-creates
UserPermissionrows for every user x permission x object combination (including descendants when propagating). - Permission checks (
user.has_perm('view_thing', obj)) hit theUserPermissiontable via a custom authentication backend -- no tree traversal at query time. - Any change (role update, binding deletion, group membership change, object moved in the tree) automatically cascades to keep
UserPermissionin sync.
Example usage
from topdownrbac.models import UserSubject, Role, RoleBinding, RestrictedObject
from django.contrib.auth.models import Permission
# Build a hierarchy
parent = RestrictedObject(parent=None); parent.save()
child = RestrictedObject(parent=parent); child.save()
# Create a role with a permission
viewer = Role.objects.create(name="Viewer")
viewer.add_permission(Permission.objects.get(codename="view_restrictedobject"))
# Bind the role to a user on the parent, propagating to all descendants
alice = UserSubject.objects.create_user(username="alice", password="secret")
RoleBinding.objects.create(
role=viewer, subject=alice, restricted_object=parent, propagate=True
)
# alice can view both parent and child automatically
assert alice.has_perm("view_restrictedobject", parent) # True
assert alice.has_perm("view_restrictedobject", child) # True
Installation
uv add django-topdownrbac
# or
pip install django-topdownrbac
For the full setup guide, custom model definitions, and DRF integration, see the walkthrough.
You can also build the docs locally: mkdocs serve
Development
Prerequisites
Getting started
Install dependencies:
uv sync
Start Postgres and the dev server:
task dev
Full reset (wipe DB, rebuild, start fresh):
task fresh
Documentation
MkDocs and its plugins (e.g. mkdocs-puml) are installed as dev dependencies by uv sync. To serve the docs locally:
task mkdocs
Running tests
task test # run all tests
task test -- -k "not benchmark" # skip benchmark tests, which can prove to be long
task test -- -v # verbose output
Linting
task lint # check with ruff
task lint:fix # auto-fix issues
Building Docker images
task build # builds both CI and production images
task security # build + Trivy vulnerability scan
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_topdownrbac-0.1.0.tar.gz.
File metadata
- Download URL: django_topdownrbac-0.1.0.tar.gz
- Upload date:
- Size: 133.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
644e80a98989c82e2796ae2a1358d10332343dec7460ac511528f05e2d747fde
|
|
| MD5 |
a0eef23e19c5959608020dbbf993a4cb
|
|
| BLAKE2b-256 |
d83b9bb3e4f5f084649a41915024eaf2806010fb299b879aca7b2de888066fee
|
Provenance
The following attestation bundles were made for django_topdownrbac-0.1.0.tar.gz:
Publisher:
release.yml on Gobijacques/django-topdownrbac
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_topdownrbac-0.1.0.tar.gz -
Subject digest:
644e80a98989c82e2796ae2a1358d10332343dec7460ac511528f05e2d747fde - Sigstore transparency entry: 1049629393
- Sigstore integration time:
-
Permalink:
Gobijacques/django-topdownrbac@a04acf6f19b3a605e6d834581aa7817942491057 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Gobijacques
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a04acf6f19b3a605e6d834581aa7817942491057 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_topdownrbac-0.1.0-py3-none-any.whl.
File metadata
- Download URL: django_topdownrbac-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.7 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 |
101160697fb2ad91942b4e373e8da2939c594d700c8824354358d0fb3c471006
|
|
| MD5 |
c7b17e841f78ac4b74a0fb808a269925
|
|
| BLAKE2b-256 |
699ea6e603718a78a543e2f704ee094b7df98c655bd4bfd99d4d7055d79b984b
|
Provenance
The following attestation bundles were made for django_topdownrbac-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Gobijacques/django-topdownrbac
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_topdownrbac-0.1.0-py3-none-any.whl -
Subject digest:
101160697fb2ad91942b4e373e8da2939c594d700c8824354358d0fb3c471006 - Sigstore transparency entry: 1049629445
- Sigstore integration time:
-
Permalink:
Gobijacques/django-topdownrbac@a04acf6f19b3a605e6d834581aa7817942491057 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Gobijacques
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a04acf6f19b3a605e6d834581aa7817942491057 -
Trigger Event:
push
-
Statement type: