Install
$ agentstack add skill-deadlymind-nanolama-drf-api ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
DRF API (viewsets, serializers, routers, schema)
When to use
Adding or reviewing a REST endpoint on this stack — a serializer, a ModelViewSet, router wiring, pagination, an export action, or the OpenAPI schema. Tenant scoping and RBAC are prerequisites here, not re-explained: your ViewSet subclasses the fail-closed tenant mixin (multi-tenancy) and declares {resource}_{action} permissions (rbac-permissions) before you add anything below.
Pattern
One ModelViewSet per resource, registered on a single DefaultRouter. Serve a light list serializer (few columns, no nested joins) for list, and a fat detail serializer for retrieve/create/update, chosen in get_serializer_class() by self.action. Pagination is a global default. Side-jobs (export, bulk ops) are custom @actions, not new endpoints. The schema is generated, never hand-written.
Steps / idioms
Split the serializers, pick one by self.action, register a single router, and inherit the tenant + RBAC mixins. One consolidated example:
# serializers.py — thin list row vs. fat detail payload
class InvoiceListSerializer(serializers.ModelSerializer):
class Meta:
model = Invoice
fields = ["id", "number", "total", "status"] # cheap list row
class InvoiceDetailSerializer(serializers.ModelSerializer):
lines = InvoiceLineSerializer(many=True, read_only=True) # nested, costly
class Meta:
model = Invoice
fields = ["id", "number", "total", "status", "lines", "notes"]
# views.py — one ViewSet; serializer chosen by action, tenant + RBAC inherited
class InvoiceViewSet(TenantScopedViewSet): # scopes queryset fail-closed
queryset = Invoice.objects.all()
permission_classes = [InvoiceRBAC] # {resource}_{action} gate
def get_serializer_class(self):
return InvoiceListSerializer if self.action == "list" else InvoiceDetailSerializer
@action(detail=False, methods=["get"]) # -> /api/invoices/export/
def export(self, request):
rows = self.filter_queryset(self.get_queryset()) # stays tenant-scoped
resp = HttpResponse(content_type="text/csv")
csv.writer(resp).writerows(rows.values_list("number", "total"))
return resp
# urls.py — one router derives the URLConf and the browsable/OpenAPI schema
router = DefaultRouter()
router.register(r"invoices", InvoiceViewSet, basename="invoice")
urlpatterns = router.urls
Set a global pagination default so every list is bounded: in settings.py, give REST_FRAMEWORK a DEFAULT_PAGINATION_CLASS of rest_framework.pagination.PageNumberPagination, a PAGE_SIZE (e.g. 25), and a DEFAULT_SCHEMA_CLASS of drf_spectacular.openapi.AutoSchema. Generate the OpenAPI schema with python manage.py spectacular --file schema.yml, and annotate non-obvious actions with @extend_schema so the generated types stay accurate — the frontend consumes this schema (see drf-zod-contract).
Throttle every API so no client can hammer it unbounded: in REST_FRAMEWORK set DEFAULT_THROTTLE_CLASSES (e.g. UserRateThrottle, AnonRateThrottle) and DEFAULT_THROTTLE_RATES (e.g. {"user": "1000/day", "anon": "100/day"}), tuned to your traffic. For a heavy @action, give it its own throttle_scope and a dedicated rate.
Adapt to your repo
Rename Invoice, InvoiceLine, and the entreprise tenant FK to your models. Confirm TenantScopedViewSet and your RBAC permission class exist (they are separate skills). Pick a pagination class that fits your UI — PageNumberPagination for page numbers, CursorPagination for infinite scroll or large offsets. Set PAGE_SIZE to your default.
Gotchas
- A single fat serializer on
listis the classic N+1 — split list vs detail and add
select_related/prefetch_related on the detail queryset (see perf-review).
- Custom
@actions bypass nothing automatically: re-runget_queryset()/
filter_queryset so they stay tenant-scoped, and gate them under RBAC.
- No global
DEFAULT_PAGINATION_CLASSmeans unbounded list responses — set it once. - Stream large exports with
StreamingHttpResponse; a fullHttpResponsebuffers the
whole CSV in memory.
get_serializer_classkeys offself.action— a typo silently falls through to the
detail serializer; assert the split in a test.
Model.save(update_fields=[...])skipsclean()/ full validation — enforce business
rules in perform_update or serializer.validate, never by relying on Model.clean firing on save.
- A serializer
source="get_x_display"only resolves when the model field declares
choices=; otherwise it silently breaks — use a SerializerMethodField instead.
- One
ScopedRateThrottlescope is a single shared bucket per user across every endpoint
using it, so a heavy action (bulk export, PDF generation) can starve unrelated endpoints — give it its own throttle_scope so the buckets don't collide.
See also
multi-tenancyrbac-permissionsdrf-zod-contractperf-review
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Deadlymind
- Source: Deadlymind/nanolama
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.