ワンクリックで
turbodrf
TurboDRF - fast Django REST framework with automatic OpenAPI, serializers, views, routers, and caching
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
TurboDRF - fast Django REST framework with automatic OpenAPI, serializers, views, routers, and caching
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Develop C++ plugins for Kate text editor using KTextEditor Framework, CMake with ECM, Qt threading, and KDE plugin architecture
Develop plugins, tools, and extensions for OpenCode AI coding agent with MCP, LSP integration, custom tools, and SDK usage
Django security - CSRF protection, authentication, sessions, login/logout, password handling, middleware, protected views
Python testing framework with powerful fixtures, parametrization, extensive plugin ecosystem, and support for async, Django, Flask testing
Python SQL toolkit and ORM with expressive query API, relationship mapping, async support, and Alembic migrations
Common Rust development pitfalls: frequent compiler errors, struct constructor patterns, test organization, and coverage enforcement for reliable codebases.
| name | turbodrf |
| description | TurboDRF - fast Django REST framework with automatic OpenAPI, serializers, views, routers, and caching |
| metadata | {"author":"mte90","version":"1.0.0","tags":["python","django","rest-api","openapi","serializers","caching"]} |
TurboDRF - Dead simple Django REST API generator with role-based permissions
Turn your Django models into fully-featured REST APIs with a mixin and a configuration method. Zero boilerplate.
TurboDRF is a Django REST Framework mixin-based library that automatically generates CRUD API endpoints for your models. Unlike traditional DRF setups requiring ViewSets and serializers, TurboDRF uses a simple mixin pattern where you declare your model inherits from TurboDRFMixin and define a turbodrf() configuration method.
Key Features:
?fields=)pip install turbodrf
# Optional: faster JSON rendering (7x faster than stdlib)
pip install turbodrf[fast]
pip install git+https://github.com/alexandercollins/turbodrf.git
INSTALLED_APPS# settings.py
INSTALLED_APPS = [
# Django apps
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party apps
'rest_framework',
'django_filters',
# TurboDRF
'turbodrf',
# Your apps
'myapp',
]
# myapp/models.py
from django.db import models
from turbodrf.mixins import TurboDRFMixin
class Book(models.Model, TurboDRFMixin):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
published_date = models.DateField()
# Define searchable fields
searchable_fields = ['title', 'author']
@classmethod
def turbodrf(cls):
return {
'fields': ['title', 'author', 'price', 'published_date']
}
# urls.py
from django.contrib import admin
from django.urls import path, include
from turbodrf import urls as turbodrf_urls
urlpatterns = [
# Admin
path('admin/', admin.site.urls),
# API with auto-configured documentation
path('api/', include(turbodrf_urls)),
]
# settings.py
TURBODRF_ROLES = {
'admin': [
# Model-level permissions
'myapp.book.read',
'myapp.book.create',
'myapp.book.update',
'myapp.book.delete',
# Field-level permissions
'myapp.book.price.read',
'myapp.book.price.write',
],
'editor': [
'myapp.book.read',
'myapp.book.update',
'myapp.book.price.read', # Read-only access to price
],
'viewer': [
'myapp.book.read',
# No access to price field
]
}
# myapp/apps.py
from django.apps import AppConfig
from django.contrib.auth import get_user_model
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
def ready(self):
User = get_user_model()
def get_user_roles(self):
# Example: Use Django groups as roles
return [group.name for group in self.groups.all()]
if not hasattr(User, 'roles'):
User.add_to_class('roles', property(get_user_roles))
Done! You now have a full REST API at /api/ with:
GET /api/books/ # List all books
POST /api/books/ # Create a new book
GET /api/books/1/ # Get a specific book
PUT /api/books/1/ # Update a book
DELETE /api/books/1/ # Delete a book
Query parameters:
GET /api/books/?search=django # Search
GET /api/books/?author__name=Smith # Filter
GET /api/books/?ordering=-price # Order
GET /api/books/?page=2&page_size=10 # Paginate
GET /api/books/?fields=title,price # Client field selection
@classmethod
def turbodrf(cls):
return {
'enabled': True, # Enable/disable API (default: True)
'endpoint': 'books', # Custom endpoint name (default: pluralized model name)
'fields': ['title', 'author'], # Fields to expose (see below)
'public_access': False, # Allow unauthenticated GET (default: False)
'lookup_field': 'pk', # URL lookup field (default: 'pk', or 'slug')
'compiled': True, # Use compiled read path (default: True)
}
All database fields:
'fields': '__all__'
Specific fields (same for list and detail):
'fields': ['title', 'author', 'price']
Different fields for list vs detail:
'fields': {
'list': ['title', 'author', 'price'],
'detail': ['title', 'description', 'author', 'author__email', 'price']
}
Access related model fields with __ notation:
'fields': [
'title',
'author__name', # ForeignKey (1 level)
'author__publisher__name', # Multi-level (2 levels)
'tags__name', # ManyToMany
]
FK fields are flattened in responses (author__name becomes author_name). M2M fields are arrays of objects:
{
"title": "Django for APIs",
"author_name": "William Vincent",
"tags": [{"name": "Python"}, {"name": "Django"}]
}
Maximum nesting depth is 3 by default. Change with TURBODRF_MAX_NESTING_DEPTH in settings.
Model @property methods work in the compiled path:
class Book(models.Model, TurboDRFMixin):
title = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
@property
def display_title(self):
return self.title.upper()
@classmethod
def turbodrf(cls):
return {
'fields': ['title', 'price', 'display_title']
}
Properties that access related objects (e.g., self.author.name) won't work in the compiled path — use author__name in the field config instead.
class Book(models.Model, TurboDRFMixin):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
@classmethod
def turbodrf(cls):
return {
'fields': {
'list': ['title', 'author', 'price'],
'detail': ['title', 'author', 'description', 'price']
}
}
TurboDRF supports three permission modes:
No permissions (development):
TURBODRF_DISABLE_PERMISSIONS = True
Django default permissions:
TURBODRF_USE_DEFAULT_PERMISSIONS = True
Role-based permissions (default):
TURBODRF_ROLES = {
'admin': [
'myapp.book.read',
'myapp.book.create',
'myapp.book.update',
'myapp.book.delete',
'myapp.book.price.read',
'myapp.book.price.write',
],
'editor': [
'myapp.book.read',
'myapp.book.update',
'myapp.book.price.read',
],
'viewer': [
'myapp.book.read',
]
}
app_label.model_name.action (read, create, update, delete)app_label.model_name.field_name.read or .writeprice.read), that field requires explicit permission for ALL rolesprice for viewers, add price.read to at least one role (like admin)TurboDRF reads user.roles — a property that returns a list of role names:
# From Django groups
User.add_to_class('roles', property(lambda self: [g.name for g in self.groups.all()]))
# From a JSONField
class User(AbstractUser):
user_roles = models.JSONField(default=list)
@property
def roles(self):
return self.user_roles
Authenticated users with no roles get 403 on all endpoints.
For runtime changes without redeployment:
TURBODRF_PERMISSION_MODE = 'database'
TURBODRF_PERMISSION_CACHE_TIMEOUT = 300 # 5 minutes
from turbodrf.models import TurboDRFRole, RolePermission, UserRole
role = TurboDRFRole.objects.create(name='editor')
RolePermission.objects.create(role=role, app_label='books', model_name='book', action='read')
UserRole.objects.create(user=user, role=role)
Permissions are checked at each level of a nested field path. For author__publisher__name:
author on Book?publisher on Author?name on Publisher?If any level fails, the field is excluded.
Users can only filter on fields they have read permission for. Filters on hidden fields are silently ignored.
class Project(models.Model, TurboDRFMixin):
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
@classmethod
def turbodrf(cls):
return {
'tenant_field': 'workspace', # mandatory wall
'owner_field': 'owner', # within-tenant rule
'bypass_owner_roles': ['manager', 'admin'], # roles ignore owner check
'fields': ['title', 'workspace', 'owner'],
}
Plus project-wide settings:
TURBODRF_TENANT_MODEL = 'accounts.Workspace'
TURBODRF_TENANT_USER_FIELD = 'workspace' # request.user.workspace → tenant
A request GET /api/projects/ from Alice (member at ABC workspace) goes through:
member has app.project.read. Pass.WHERE project.workspace_id = <Alice's workspace>AND project.owner_id = <Alice's user id>title, workspace, owner but maybe not all configured fields. Hidden ones are removed from the response.# Multi-tenant SaaS — most common case
{'tenant_field': 'store', 'owner_field': 'customer', 'bypass_owner_roles': ['staff']}
# Personal data app (no tenant)
{'owner_field': 'author', 'bypass_owner_roles': ['admin']}
# Reference data (currencies, country codes — not tenant-scoped)
{'tenancy': 'shared'}
# M2M membership (Slack channels, Linear projects)
{'visibility': [Tenant('workspace'), Members('participants')]}
# Power-form composition (when sugar doesn't fit)
{'visibility': [Tenant('workspace'), Either(Owner('owner'), Members('shared_with'))]}
See docs/tenancy.md for the full predicate vocabulary, hard-fail-at-startup behavior, and 404-vs-403 semantics.
For Postgres deployments, TurboDRF can generate Row Level Security policies that enforce the same rules at the database layer. See docs/rls.md.
Fields like password, token, and secret_key are never exposed:
TURBODRF_SENSITIVE_FIELDS = [
'password', 'password_hash', 'secret_key', 'api_key',
'token', 'access_token', 'refresh_token', 'session_key',
]
If a permission check fails due to an error, access is denied. TurboDRF never grants access on exception.
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'turbodrf.exceptions.turbodrf_exception_handler',
}
{
"error": {
"status": 403,
"code": "permission_denied",
"message": "You do not have permission to perform this action."
}
}
TurboDRF includes startup gates that detect:
These gates refuse to boot if unsafe configurations are detected, preventing cross-permission read leaks.
Auto-generated Swagger UI and ReDoc:
/api/swagger//api/redoc/Disable in production:
TURBODRF_ENABLE_DOCS = False
# Validate configuration
python manage.py turbodrf_check
# Performance benchmark
python manage.py turbodrf_benchmark
# Explain query execution
python manage.py turbodrf_explain
Key settings:
| Setting | Description |
|---|---|
TURBODRF_ROLES | Role-based permissions dict |
TURBODRF_DISABLE_PERMISSIONS | Disable all permissions |
TURBODRF_USE_DEFAULT_PERMISSIONS | Use Django default permissions |
TURBODRF_PERMISSION_MODE | 'static' or 'database' |
TURBODRF_PERMISSION_CACHE_TIMEOUT | Permission cache TTL (seconds) |
TURBODRF_TENANT_MODEL | Default tenant model |
TURBODRF_TENANT_USER_FIELD | User's tenant field |
TURBODRF_SENSITIVE_FIELDS | Fields to hide from all users |
TURBODRF_ENABLE_DOCS | Enable Swagger/ReDoc |
TURBODRF_MAX_NESTING_DEPTH | Max nested field depth |
TURBODRF_USE_FILTERS | Enable Django filters |
TURBODRF_DEFAULT_PAGE_SIZE | Default pagination page size |
TURBODRF_SENSITIVE_FIELDS | Fields to hide from all users |
models.py:
from django.db import models
from turbodrf.mixins import TurboDRFMixin
class Author(models.Model, TurboDRFMixin):
name = models.CharField(max_length=100)
email = models.EmailField()
@classmethod
def turbodrf(cls):
return {
'fields': ['name', 'email']
}
class Book(models.Model, TurboDRFMixin):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
@classmethod
def turbodrf(cls):
return {
'fields': {
'list': ['title', 'author__name'],
'detail': ['title', 'author__name', 'author__email', 'price']
}
}
settings.py:
INSTALLED_APPS = [
'rest_framework',
'turbodrf',
'myapp',
]
TURBODRF_ROLES = {
'admin': [
'myapp.book.read',
'myapp.book.create',
'myapp.book.update',
'myapp.book.delete',
'myapp.book.price.read',
'myapp.book.price.write',
],
'editor': [
'myapp.book.read',
'myapp.book.update',
'myapp.book.price.read',
],
'viewer': [
'myapp.book.read',
]
}
urls.py:
from django.contrib import admin
from django.urls import path, include
from turbodrf import urls as turbodrf_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(turbodrf_urls)),
]
Define fields explicitly rather than __all__ for better control.
Use Django's form validation or custom validators:
def validate_title(value):
if Book.objects.filter(title=value).exclude(pk=self.instance.pk).exists():
raise serializers.ValidationError("Title already exists")
return value
Restrict access appropriately:
TURBODRF_ROLES = {
'public': ['myapp.book.read'],
'staff': [
'myapp.book.read',
'myapp.book.create',
'myapp.book.update',
'myapp.book.delete',
],
}
Users can only filter on fields they have read permission for.
Always include sensitive fields in the deny-list:
TURBODRF_SENSITIVE_FIELDS = [
'password', 'token', 'api_key', 'secret_key',
]
If you get import errors, ensure TurboDRF is properly installed:
pip list | grep turbodrf
If no endpoints appear, check that:
TurboDRFMixinturbodrf() classmethod'enabled': False)If you get 403 errors:
TURBODRF_ROLESroles propertyIf startup gate fires due to M2M/FK traversals:
turbodrf() fields list'compiled': False on the parent modelTURBODRF_ALLOW_UNSAFE_COMPILED_M2M = True (not recommended)