Skip to main content

🚀 django_resaas

The framework you've been missing for building multi-tenant SaaS apps in Django — without reinventing the wheel on every project.

PyPI Python Django License: MIT Status


If you've ever built a SaaS API in Django, you know the drill: multi-tenancy, per-group and per-branch permissions, soft delete, file uploads, PDF generation, i18n, plan-based billing… all of it again, project after project.

django_resaas solves that part once and for all. It's a framework built on top of Django + DRF that gives any application a production-ready foundation: multi-tenancy, RBAC, smart CRUD, dynamic search, per-client feature modules, and billing — so your team can focus on what actually matters: the business.

pip install django_resaas

Table of contents


🎯 Why it exists

"Building SaaS shouldn't be repetitive."

Every multi-tenant SaaS app ends up needing the same set of building blocks. django_resaas ships them ready-made, tested, and consistent with each other:

Without django_resaas With django_resaas
Multi-tenancy hand-rolled on every project BaseModel already ships entity + branch
Permissions checked manually in every view Automatic RBAC via Entity + Branch + Group
CRUD written from scratch for every resource BaseAPIView gives full CRUD in ~5 lines
Destructive delete with no way back Native soft delete + restore + hard delete
Custom search per endpoint Automatic dynamic search (?search=)
"All or nothing" modules Per-client module activation (App + EntityApp)
Translations scattered across the code Central i18n system (DB + lang/ files)

✨ Features

  • 🔐 RBAC — permissions by User + Group + context (Entity/Branch)
  • 🏢 Native multi-tenancy — isolation by Entity and Branch
  • ⚡ Automatic CRUD — BaseAPIView with pagination, ordering, filtering and permissions built in
  • 🔎 Dynamic search — automatic search across text fields and relations
  • ♻️ Soft delete — delete() / restore() / hard_delete() + dedicated managers
  • 🧩 Per-client modules — toggle features on/off per entity without a deploy (App + EntityApp)
  • 📎 Files & PDF — secure uploads, automatic metadata, PDF generation (WeasyPrint)
  • 🔑 JWT auth + 2FA — simplejwt, OTP (pyotp) and QR codes built in
  • 🌍 Built-in i18n — file-based translations (pt-pt, en-us, es-es, fr-fr) and database-backed
  • 🌐 Dedicated middlewares — tenant context, frontend protection and file access control
  • 💵 Native money support (django-money)

⚙️ Installation & setup

pip install django_resaas
# or, for local development:
pip install -e .
# settings.py
INSTALLED_APPS = [
    ...
    "django_resaas",
    "hr",  # example module included
]

MIDDLEWARE = [
    ...
    "django_resaas.core.middleware.tenant.TenantContextMiddleware",
    "django_resaas.core.middleware.front_end.FrontEndMiddleware",
]
make migrate
make superuser
make run          # http://0.0.0.0:7002

🧠 Architecture

User
 ↓
Person
 ↓
Employee (HR)
 ↓
Entity (tenant)
 ↓
Branch
 ↓
Groups + Permissions

Key concepts:

Concept Role
Entity The tenant — typically the client/company
Branch A unit/location within an Entity
Person Human data (name, email, contacts)
User Authentication
BranchUserGroup Links User + Branch + Group, allowing multiple groups per branch

🧪 Full example in 3 files

Model

from django.db import models
from django_resaas.core.base.models import BaseModel

class Employee(BaseModel):
    person = models.ForeignKey("django_resaas.Person", on_delete=models.CASCADE)
    role = models.CharField(max_length=100)

BaseModel already ships entity, branch, created_at/updated_at, created_by/updated_by and soft delete.

Serializer

from django_resaas.core.base.serializers import BaseSerializer

class EmployeeSerializer(BaseSerializer):
    class Meta:
        model = Employee
        fields = "__all__"

View

from django_resaas.core.base.views import BaseAPIView, registerView

@registerView(module="hr")
class EmployeeView(BaseAPIView):
    queryset = Employee.objects.all()
    serializer_class = EmployeeSerializer

That's enough to automatically get: full CRUD, multi-tenant isolation, permissions, search, soft delete, restore, and protection based on the active module.


🔐 Multi-tenancy & RBAC

Tenant context is never trusted from raw client-supplied values. It travels as a single signed, short-lived token, issued by the API after checking the user actually has access to the Entity/Branch/Group requested.

1. Issue a context, once the user is authenticated:

POST /api/resaas/context/
Authorization: Bearer <access_token>

{
  "entity_id": "...",
  "branch_id": "...",   // optional
  "group_id": "..."     // optional
}

ResaasContextService validates access (via EntityUser / BranchUser / BranchUserGroup, with a superuser/entity-admin bypass) and signs the result with django.core.signing — versioned and bound to a TTL (1h by default, RESAAS_CONTEXT_TTL setting):

{ "token": "<signed-context-token>", "context": { "entity_id": "...", "branch_id": "...", "group_id": "..." } }

2. Send it back on every request, alongside auth and language — three headers, one job each:

Header Purpose
Authorization Bearer <JWT> — who you are
X-RESAAS-Context signed tenant context — where you're operating (entity/branch/group)
L active language id

TenantContextMiddleware decodes the token and verifies its signature and expiry on every request, exposing:

request.entity_type_id
request.entity_id
request.branch_id
request.group_id

BaseAPIView then re-validates that the context still belongs to the authenticated user (ResaasContextService.validate_for_user) before touching the queryset — a forged, expired, or replayed token from another user/tenant is rejected even if it was valid at issue time.

If a resource's module isn't active for the Entity, access is blocked automatically — no extra code in the view.

⚠️ Breaking change from earlier versions: the old scheme (raw ET / E / S / G headers sent directly by the client) has been replaced by the signed X-RESAAS-Context token above. If you're upgrading, swap those headers for a call to POST /resaas/context/ and forward the returned token instead.


🔁 Soft delete

obj.delete()        # soft delete
obj.restore()       # restore
obj.hard_delete()   # permanently delete
Model.objects           # active only
Model.deleted_objects    # deleted only
Model.all_objects        # everything

🔎 Automatic search & filters

GET /api/employees/?search=john

BaseAPIView automatically searches text fields and relations (ForeignKey), with no per-endpoint configuration required.


🧩 Per-client modules

Each Entity only sees the modules it has activated:

Entity Module Status
Company A HR ✅
Company A CRM ❌

Activation is a direct App ↔ Entity link via EntityApp (toggled with its state field):

EntityApp.objects.get_or_create(app=app, entity=entity, state='Active')

There is no plan-based billing layer yet (no Plan/EntityPlan model, no automatic plan-to-module sync) - that's tracked under Roadmap. Module activation today is a direct per-entity toggle, as used by python manage.py create_root (see docs/development/management-commands.md).


🌐 Middlewares

Middleware Responsibility
TenantContextMiddleware Decodes the signed X-RESAAS-Context token and resolves entity, branch, group (L header for language)
FrontEndMiddleware Protects access via FEK/FEP frontend credentials and route/HTTP-method permissions
FileAccessMiddleware Controls access to protected files and media

🌍 Internationalization (i18n)

Translations are resolved in cascade — database first, then each app's lang/ files — with automatic caching:

from django_resaas.core.utils.translate import Translate

Translate.tdc(request, "Register")

Languages included out of the box: pt-pt, en-us, es-es, fr-fr.


🛠 CLI / management commands

python manage.py setup             # initial SaaS bootstrap
python manage.py create_entity     # creates a new Entity (tenant)
python manage.py create_root       # creates the root user
python manage.py sync_language     # loads the default languages
python manage.py sync_actions      # syncs views registered in VIEW_REGISTRY
python manage.py check              # Django's system check framework
python manage.py check_metano       # validates compliance with the MetanoStack standard

🧰 Tech stack

Layer Technology
Backend Django 5.2 + Django REST Framework
Auth djangorestframework-simplejwt, 2FA (pyotp, qrcode)
Database PostgreSQL (psycopg)
Documents WeasyPrint (PDF), python-barcode
Filtering django-filter
Money django-money
Deployment Gunicorn

📚 Documentation

Full technical documentation lives in docs/:


🚀 Roadmap

  • Stripe integration
  • Billing dashboard
  • Resource auto-router
  • Action auditing
  • Multi-tenant logs
  • Permission cache (Redis)

🤝 Contributing

Pull requests are welcome. For larger changes, please open an issue first to discuss direction.

git clone https://github.com/metanochava/django_resaas.git
cd django_resaas
pip install -e .
make check

📄 License

Distributed under the MIT license.


Made by Metano Chavana

Release files for django-resaas 0.0.587

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-resaas 0.0.587
File Size Uploaded
django_resaas-0.0.587.tar.gz 500.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-resaas 0.0.587
File Interpreter ABI Platform
django_resaas-0.0.587-py3-none-any.whl Python 3 none any Details

Total release size: 1.2 MB

Release files / django_resaas-0.0.587.tar.gz

Download URL django_resaas-0.0.587.tar.gz
Size 500.7 kB
Tags Source
SHA-256 checksum
How to use checksums
1883c0e8115e1272362ffd1c7c5eb25fbc1edc8241a84503c6a69750642fdee8
BLAKE2b-256 checksum
How to use checksums
c31fdaca59060a5c90b6d0d14c7da3e3c08e9197cd2fa3d6d96ffb9c07d3709b
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 Sep 19, 2026.

Transparency log

Release files / django_resaas-0.0.587-py3-none-any.whl

Download URL django_resaas-0.0.587-py3-none-any.whl
Size 747.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3b10dbdb1558564ea7a8481c21539d9ed0d47d6d0623f54522199ce30b0b6362
BLAKE2b-256 checksum
How to use checksums
7bca0508716839e7f24470a73986a362796f0a655b8751bb75d524ec0f6f143a
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 Sep 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.587 This release

2 release files

0.0.99

2 release files

0.0.97

2 release files

0.0.96

2 release files

0.0.94

2 release files

0.0.93

2 release files

0.0.62

2 release files

0.0.61

2 release files

0.0.60

2 release files

0.0.59

2 release files

0.0.58

2 release files

0.0.57

2 release files

0.0.56

2 release files

0.0.55

2 release files

0.0.54

2 release files

0.0.49

2 release files

0.0.48

2 release files

0.0.47

2 release files

0.0.46

2 release files

0.0.45

2 release files

0.0.44

2 release files

0.0.43

2 release files

0.0.42

2 release files

0.0.41

2 release files

0.0.40

2 release files

0.0.39

2 release files

0.0.38

2 release files

0.0.37

2 release files

0.0.36

2 release files

0.0.35

2 release files

0.0.34

2 release files

0.0.33

2 release files

0.0.32

2 release files

0.0.31

2 release files

0.0.30

2 release files

0.0.29

2 release files

0.0.28

2 release files

0.0.27

2 release files

0.0.26

2 release files

0.0.25

2 release files

0.0.24

2 release files

0.0.23

2 release files

0.0.22

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page