Compose your own viewset¶
ServiceViewSet is the full-CRUD composition of every per-action
mixin. When you want fewer actions, compose the mixins yourself — they
are part of the public API.
Read-only viewset¶
SelectorViewSet is a pre-built composition of SelectorListMixin +
SelectorRetrieveMixin + ActionSerializerResolver + DRF's GenericViewSet:
from rest_framework_services import SelectorSpec, SelectorViewSet
class AuthorReadOnly(SelectorViewSet):
queryset = Author.objects.all()
action_specs = {
"list": SelectorSpec(selector=list_authors, output_serializer=AuthorDetailSerializer),
"retrieve": SelectorSpec(selector=get_author, output_serializer=AuthorDetailSerializer),
}
Or compose it yourself, if you want to mix in something custom:
from rest_framework.viewsets import GenericViewSet
from rest_framework_services import (
ActionSerializerResolver,
SelectorListMixin,
SelectorRetrieveMixin,
SelectorSpec,
)
class AuthorReadOnly(SelectorListMixin, SelectorRetrieveMixin, ActionSerializerResolver, GenericViewSet):
queryset = Author.objects.all()
action_specs = {
"list": SelectorSpec(selector=list_authors, output_serializer=AuthorDetailSerializer),
"retrieve": SelectorSpec(selector=get_author, output_serializer=AuthorDetailSerializer),
}
Create + retrieve only¶
Useful for resources that are written once and then read, never updated.
from rest_framework.viewsets import GenericViewSet
from rest_framework_services import (
ActionSerializerResolver,
SelectorRetrieveMixin,
SelectorSpec,
ServiceCreateMixin,
ServiceSpec,
)
class TicketViewSet(
ServiceCreateMixin,
SelectorRetrieveMixin,
ActionSerializerResolver,
GenericViewSet,
):
queryset = Ticket.objects.all()
action_specs = {
"retrieve": SelectorSpec(
selector=get_ticket,
output_serializer=TicketDetailSerializer,
),
"create": ServiceSpec(
service=open_ticket,
input_serializer=OpenTicketInput,
output_serializer=TicketDetailSerializer,
),
}
Available mixins¶
| Mixin | Action | DRF method |
|---|---|---|
ServiceCreateMixin |
create |
POST |
ServiceUpdateMixin |
update / partial_update |
PUT / PATCH |
ServiceDestroyMixin |
destroy |
DELETE |
SelectorListMixin |
list |
GET (collection) |
SelectorRetrieveMixin |
retrieve |
GET (detail) |
ActionSerializerResolver |
— | per-action output_serializer dispatch |
MutationFlowMixin |
— | the building block for service-backed action flow on bespoke shapes that don't fit the existing five mixins |
ActionSerializerResolver is independent of any action and is safe to mix
into any viewset (or skip if every action uses the same serializer via
DRF's serializer_class).
When to reach for MutationFlowMixin¶
Almost never directly — ServiceCreateMixin etc. compose it. Reach
for it when you have a non-DRF action shape that needs the same
validate-dispatch-render flow (e.g. a websocket message handler, a
GraphQL mutation backend). It is exported precisely so you can build
those shapes without copying the dispatch code.