View Decorators¶
Django Ninja AIO provides decorator utilities for composing view behavior and attaching decorators to CRUD operations declaratively.
-
@action
Custom actions for ViewSets
-
@on
Detail actions with automatic object pre-fetch
-
decorate_view
Compose multiple decorators on sync/async views
-
extra_decorators
Declarative per-operation decorators on ViewSets
-
M2M Decorators
Custom decorators for relation endpoints
-
api_get/api_post
Endpoint decorators with built-in decorator support
@action (custom actions)¶
Decorator for adding custom endpoints to ViewSets. Supports detail/list actions, multiple HTTP methods, auth inheritance, and full OpenAPI metadata.
Key features:
detail=Trueauto-adds{pk}to URL, renamed to match model PK fieldurl_pathdefaults to method name with_→-auth=NOT_SETinherits from viewset per-verb auth- Actions survive
disable=["all"]— always registered - Multiple methods create separate routes:
methods=["get", "post"]
See APIViewSet @action for full parameter reference.
@on (detail action shorthand)¶
Shorthand over @action for detail endpoints that operate on a pre-fetched model instance. Instead of manually fetching the object and running permission hooks, @on does it automatically — your handler receives obj ready to use.
Comparison with @action:
@action(detail=True, methods=["post"], url_path="publish", response={200: ArticleSchema})
async def publish(self, request, pk):
await self.on_before_operation(request, "publish")
obj = await self.model_util.get_object(request, pk)
await self.on_before_object_permission(request, "publish", obj)
obj.status = "published"
await obj.asave(update_fields=["status"])
return Status(200, await self.model_util.read_s(self.schema_out, request, obj))
What @on does automatically:
- Calls
on_before_operation(request, action_name)— view-level hooks/permissions - Fetches
obj = await model_util.get_object(request, pk)— raises 404 if not found - Calls
on_before_object_operation(request, action_name, obj)— object-level hooks/permissions - Passes
objto your handler
Parameters:
| Parameter | Default | Description |
|---|---|---|
action_name |
required | URL path segment and operation name |
methods |
["post"] |
HTTP methods |
url_path |
action_name |
Override the URL segment |
auth |
NOT_SET |
Inherits from viewset per-verb auth |
response |
NOT_SET |
Response schema |
summary, description, tags, deprecated, decorators, throttle, include_in_schema, openapi_extra |
— | Standard Ninja endpoint metadata |
Note
@on always sets detail=True. The handler must be async since object fetching is async.
Tip
Works seamlessly with PermissionViewSetMixin — on_before_object_operation is always called regardless of _has_object_hooks.
decorate_view¶
Compose multiple decorators into a single view wrapper.
Behavior:
- Order matches normal stacking:
@d1over@d2≡d1(d2(view)) - Works with both sync and async views
Nonevalues are ignored — useful for conditional decoration
Note
decorate_view does not add an extra wrapper layer. Each decorator should preserve metadata itself (e.g., via functools.wraps).
APIViewSet.extra_decorators¶
Attach decorators to auto-generated CRUD operations without redefining views:
from ninja_aio.schemas.helpers import DecoratorsSchema
@api.viewset(MyModel)
class MyViewSet(APIViewSet):
extra_decorators = DecoratorsSchema(
list=[require_auth, cache_page(30)],
retrieve=[require_auth],
create=[require_auth],
update=[require_auth],
delete=[require_auth],
)
Available operations¶
| Field | Applies to |
|---|---|
list |
GET / — List all items |
retrieve |
GET /{pk} — Get single item |
create |
POST / — Create item |
update |
PATCH /{pk} — Update item |
delete |
DELETE /{pk} — Delete item |
Tip
These decorators are applied in combination with built-in decorators (unique_view, paginate) using decorate_view internally.
M2M Relation Decorators¶
Apply custom decorators to Many-to-Many relation endpoints via get_decorators and post_decorators:
from ninja_aio.schemas import M2MRelationSchema
M2MRelationSchema(
model=Tag,
related_name="tags",
get_decorators=[cache_decorator, log_decorator], # GET (list related)
post_decorators=[rate_limit_decorator], # POST (add/remove)
)
| Parameter | Applies to |
|---|---|
get_decorators |
GET /{pk}/tag — List related items |
post_decorators |
POST /{pk}/tag — Add/remove relations |
See APIViewSet M2M Relations for more details.
api_get / api_post with Decorators¶
Endpoint decorators accept a decorators parameter for inline decorator composition:
from ninja.pagination import PageNumberPagination
from ninja_aio.decorators.operations import api_get
from ninja_aio.decorators import unique_view
from ninja.pagination import paginate
@api.viewset(models.Book)
class BookAPI(APIViewSet):
@api_get(
"/custom-get",
response={200: list[GenericMessageSchema]},
decorators=[paginate(PageNumberPagination), unique_view("test-unique-view")],
)
async def get_test(self, request):
return [{"message": "This is a custom GET method in BookAPI"}]
How decorators are applied
- Provide decorators as a list — they are applied in reverse order internally
paginate(PageNumberPagination)enables async pagination on the handlerunique_view(name)marks the route as unique to avoid duplicate registration- Works with
@api.viewset(Model)classes extendingAPIViewSet
See Also¶
-
APIViewSet
Complete CRUD view generation with decorator support
-
APIView
Base view class for custom endpoints
-
Mixins
Reusable filtering and query behaviors
-
Pagination
Async pagination support for list endpoints