All projects

Author & maintainer · Open source · MIT

TurboDRF

Django REST APIs with role, row and field permissions.

Role
Author & maintainer
Years
Open source · MIT
Stack
Python 3.10 – 3.14Django 4.2 · 5.2 · 6.0Django REST Frameworkdjango-filterdrf-yasg

Overview

TurboDRF turns Django models into REST APIs. Add a mixin, describe the model in a turbodrf() method and register the router. You get list, detail, create, update and delete endpoints, with search, filtering, ordering, pagination and ?fields= selection.

What each role may do lives in one setting, TURBODRF_ROLES. Which rows a user can see lives on the model. Both are checked on every request.

Why I built it

Every Django project I started needed the same ViewSets, the same permission classes and the same tenant checks. I'd write them again, get one slightly wrong, and find out later. TurboDRF is that code written once, with the safe choice as the default. It's still small enough to read end to end.

Three layers on every request

It won't start with a bad config

Most permission bugs are configuration bugs, so TurboDRF checks at startup. The app refuses to boot when:

Rows outside your access return a 404 instead of a 403, so the API never confirms they exist. When in doubt, it fails closed.

Fast reads, and tools to check them

List views skip DRF serializers by default and build .values() queries instead. turbodrf_explain prints the query plan each role gets, with the SQL if you want it. turbodrf_check validates the whole config and turbodrf_benchmark times your endpoints. JSON rendering through msgspec or orjson is an optional extra.

Endpoints of your own go through @turbodrf_action and inherit the same tenant and row scoping. Swagger and ReDoc come built in, and each caller's schema only lists what their role can reach.

What it looks like

models.py
from django.db import models
from turbodrf.mixins import TurboDRFMixin

class Project(models.Model, TurboDRFMixin):
    title = models.CharField(max_length=200)
    workspace = models.ForeignKey("accounts.Workspace", on_delete=models.CASCADE)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    searchable_fields = ["title"]

    @classmethod
    def turbodrf(cls):
        return {
            "fields": ["title", "workspace", "owner"],
            "tenant_field": "workspace",        # the tenant wall
            "owner_field": "owner",             # members see only their own rows
            "bypass_owner_roles": ["manager"],  # managers see the whole workspace
        }
settings.py · urls.py
# settings.py
TURBODRF_TENANT_MODEL = "accounts.Workspace"
TURBODRF_TENANT_USER_FIELD = "workspace"
TURBODRF_ROLES = {
    "member":  ["projects.project.read", "projects.project.create"],
    "manager": ["projects.project.read", "projects.project.update"],
}

# urls.py
from turbodrf.router import TurboDRFRouter

router = TurboDRFRouter()
urlpatterns = [path("api/", include(router.urls))]

Install

terminal
pip install turbodrf
pip install "turbodrf[fast]"   # msgspec or orjson for JSON rendering

The full guide, from the first model to tenancy and the management commands, is at turbodrf.com/docs.

Where it runs

The APIs behind Wealth MS and the bynoon CRM are both built on TurboDRF. Building Wealth MS turned up bugs in the compiled read path. They were fixed in 0.5.2.

Recent releases

v0.6.1 22 Oct 2026

Models with many-to-many fields use the compiled read path again on Django 6.0. Out-of-range IDs on Django 4.2 return 404 or 400 instead of a 500. CI now tests the Django version each job says it does.

v0.6.0 22 Oct 2026

A review of the whole framework. Field rules now cover anonymous callers through a guest role. Nested values from rows you can't see render as null. List and detail output match exactly, and the OpenAPI schema is built for each caller.

v0.5.2 22 Oct 2026

Fixes to the compiled read path, including a ?fields= request that could skip field-level rules.

v0.5.1 12 Jul 2026

A high-severity fix. On custom user models whose primary key isn't called id, cached permission snapshots could be shared between users.

v0.5.0 8 Jul 2026

Security hardening, custom endpoints, read-only models, http_methods allow-lists, full_clean on writes and a conformance suite. Postgres RLS support was removed.

Numbers

Latest
0.6.1
Beta
Test coverage
95.39%
4,470 statements
Python
3.10 to 3.14
Django
4.2, 5.2, 6.0
tested in CI
DRF
3.14+
Licence
MIT

Reporting a security issue

Use GitHub's private vulnerability reporting on the repo. Fixes go into the 0.6.x line. The threat model and the known limits are written up in docs/security.md.

More projects

All projects