django-rls-tenants
Database-enforced multitenancy for Django using PostgreSQL
Row-Level Security.
Every query -- ORM, raw SQL, dbshell -- is filtered by the database itself.
Missing tenant context returns zero rows, never leaks data.
Why this library?
Existing Django multitenancy libraries enforce isolation at the application
level — one missed filter and data leaks across tenants. django-rls-tenants
pushes enforcement to PostgreSQL itself using Row-Level Security. Every query —
ORM, raw SQL, dbshell — is filtered by the database. Missing tenant context
returns zero rows, never leaked data.
Learn more about the RLS approach →
Features
- Database-enforced isolation -- RLS policies protect tenant tables across ORM
queries, raw SQL,
dbshell, and data migrations when using a database role subject to RLS (not a superuser orBYPASSRLSrole; system checkW005warns about those). It guards against omitted tenant scoping, not arbitrary SQL on the app connection -- see the security model. - Fail-closed by default -- missing tenant context returns zero rows; optional
STRICT_MODEraisesNoTenantContextErroron unscopedTenantQuerySetevaluation. - Automatic query scoping --
RLSProtectedModeladds the tenant FK, the RLS policy, and a tenant-scoped manager. - Index-friendly by design -- the manager's
WHERE tenant_id = Xis what reaches the planner; the policy alone is a post-scan filter. Composite(tenant, ...)indexes, partial indexes, joins and the v1.3.0 InitPlan form, with measuredEXPLAINplans. Performance guide → - Tenant-aware Django admin --
RLSTenantModelAdminscopes changelists, forms, and related dropdowns to the current tenant, with a tenant switcher for cross-tenant admins. Admin guide → - Native Celery integration --
@rls_taskcarries the active tenant context from enqueue to worker, including across chains, groups, and chords (pip install "django-rls-tenants[celery]"). Celery guide → - Async context managers --
async with async_tenant_context(...)for async views, consumers and tasks; tenant state is set in the coroutine, so the async ORM is scoped. Async context managers → · Async deployment guide → - Raw SQL helpers --
safe_tenant_sql()builds a tenant-filter predicate;current_tenant_value_sql()returns the current tenant ID expression for inserts and projections. Both reuse the expressions used by RLS policies. Raw SQL guide → - M2M isolation -- auto-detected subquery-based RLS policies on M2M through tables.
- Single schema, single database -- no schema-per-tenant overhead, no connection routing.
Quick Start
pip install django-rls-tenants
# settings.py
INSTALLED_APPS = [..."django_rls_tenants"]
RLS_TENANTS = {
"TENANT_MODEL": "myapp.Tenant", # required
}
MIDDLEWARE = [..."django_rls_tenants.RLSTenantMiddleware"]
# models.py
from django_rls_tenants import RLSProtectedModel
class Order(RLSProtectedModel):
title = models.CharField(max_length=255)
# tenant FK + RLS policy added automatically
python manage.py migrate
python manage.py check_rls # verify policies are in place
Full tutorial and documentation → Something not working? Start with the Troubleshooting page (symptom / cause / fix).
Want to see it in action first? Check out the example project --
cd example && docker compose up, then open http://localhost:8000.
Comparison with Alternatives
| Feature | django-rls-tenants | django-tenants | django-multitenant |
|---|---|---|---|
| Isolation mechanism | RLS policies | Separate schemas | ORM rewriting |
| Raw SQL protected | Yes | Yes (schemas) | No |
| Single schema | Yes | No | Yes |
| No connection routing | Yes | No | Depends |
| Fail-closed on missing ctx | Yes | N/A | No |
| Works with any API layer | Yes | Yes | Yes |
Used in Production
Are you using django-rls-tenants in production? We'd love to hear about it.
Open a discussion →
Requirements
| Dependency | Version |
|---|---|
| Python | 3.12, 3.13, 3.14 |
| Django | 5.2, 6.0, 6.1 |
| PostgreSQL | 15, 16, 17, 18 |
See the supported-versions policy for how these lists change.
Contributing
Contributions are welcome! See the contributing guide to get started. This project is governed by the Contributor Covenant Code of Conduct.
License
Metadata
Release files for django-rls-tenants 1.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_rls_tenants-1.4.0.tar.gz | 293.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_rls_tenants-1.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 411.0 kB
Release files / django_rls_tenants-1.4.0.tar.gz
| Download URL | django_rls_tenants-1.4.0.tar.gz |
|---|---|
| Size | 293.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
07376d320b5862d3d52974ea3bddf6a4a8b87a7dad6ce53c6d2937ade1743545
|
|
BLAKE2b-256 checksum How to use checksums |
5c935146114a2de4a181d3421e86ef59a473bb90a4a1c708c52cb4a4b187680e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / django_rls_tenants-1.4.0-py3-none-any.whl
| Download URL | django_rls_tenants-1.4.0-py3-none-any.whl |
|---|---|
| Size | 117.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fdde790d906ef7acadb6a6c864c3385ea978858d8d9ddb3236a090a6235a496a
|
|
BLAKE2b-256 checksum How to use checksums |
249b8459091d7aab7f0deadcc5a1c04a3a7afd600d410569b0038c0b143422a0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency log