Viewsets¶
Full CRUD¶
ServiceViewSet ¶
Bases: ServiceCreateMixin, ServiceUpdateMixin, ServiceDestroyMixin, SelectorListMixin, SelectorRetrieveMixin, ActionSerializerResolver, GenericViewSet
Router-compatible viewset wiring services and selectors.
Composes :class:ServiceCreateMixin, :class:ServiceUpdateMixin,
:class:ServiceDestroyMixin, :class:SelectorListMixin,
:class:SelectorRetrieveMixin, and :class:ActionSerializerResolver
over :class:~rest_framework.viewsets.GenericViewSet. See those classes
for the configurable attributes.
SelectorViewSet ¶
Bases: SelectorListMixin, SelectorRetrieveMixin, ActionSerializerResolver, GenericViewSet
Read-only viewset for list + retrieve.
Composes :class:SelectorListMixin, :class:SelectorRetrieveMixin, and
:class:ActionSerializerResolver over
:class:~rest_framework.viewsets.GenericViewSet.
Per-action mixins¶
ServiceCreateMixin ¶
Bases: MutationFlowMixin, _ActionSpecsMixin
Provides the create action; reads its config from action_specs.
Set action_specs["create"] to a
:class:~rest_framework_services.types.service_spec.ServiceSpec.
When the "create" key is absent the action raises
:exc:~rest_framework.exceptions.MethodNotAllowed. A non-ServiceSpec
entry (e.g. a :class:~rest_framework_services.types.selector_spec.SelectorSpec)
raises :exc:~django.core.exceptions.ImproperlyConfigured.
ServiceUpdateMixin ¶
Bases: MutationFlowMixin, _ActionSpecsMixin
Provides update (PUT) and partial_update (PATCH) actions.
Looks up the instance via DRF's get_object(). Reads its config from
action_specs["update"]; when that key is absent both actions raise
:exc:~rest_framework.exceptions.MethodNotAllowed. A non-ServiceSpec
entry raises :exc:~django.core.exceptions.ImproperlyConfigured.
ServiceDestroyMixin ¶
Bases: MutationFlowMixin, _ActionSpecsMixin
Provides the destroy action.
Looks up the instance via DRF's get_object(). Reads its config from
action_specs["destroy"]; when that key is absent the action raises
:exc:~rest_framework.exceptions.MethodNotAllowed. A non-ServiceSpec
entry raises :exc:~django.core.exceptions.ImproperlyConfigured.
SelectorListMixin ¶
Bases: ListModelMixin, _ActionSpecsMixin
Compose with :class:~rest_framework.viewsets.GenericViewSet.
When action_specs["list"] is a
:class:~rest_framework_services.types.selector_spec.SelectorSpec with
a non-None selector, get_queryset() invokes it instead of
returning the configured queryset. The rest of DRF's list flow —
filter backends, pagination, serialization — is unchanged.
action_specs["list"] = SelectorSpec(selector=None) or an absent
"list" key both fall through to DRF's default get_queryset().
Any other entry type raises
:exc:~django.core.exceptions.ImproperlyConfigured.
get_selector_kwargs ¶
Hook for additional kwargs available to the selector signature.
SelectorRetrieveMixin ¶
Bases: RetrieveModelMixin, _ActionSpecsMixin
Compose with :class:~rest_framework.viewsets.GenericViewSet.
When action_specs["retrieve"] is a
:class:~rest_framework_services.types.selector_spec.SelectorSpec with
a non-None selector, get_object() invokes it instead of
falling through to DRF's standard lookup. The selector receives the
URL kwargs plus the standard pool. Returning None or raising
Model.DoesNotExist results in a 404.
action_specs["retrieve"] = SelectorSpec(selector=None) or an absent
"retrieve" key both fall through to DRF's default get_object().
Any other entry type raises
:exc:~django.core.exceptions.ImproperlyConfigured.
The selector applies wherever get_object() is called, including from
update/destroy actions composed alongside this mixin. If you need an
action-specific override, do it explicitly in your own get_object().
Action-serializer dispatch¶
ActionSerializerResolver ¶
Bases: _ActionSpecsMixin
Resolve get_serializer_class() from action_specs.
Consults the action_specs map for an output_serializer on the
active action's :class:SelectorSpec or :class:ServiceSpec entry,
then falls back to DRF's standard serializer_class attribute (and
raises the usual DRF AssertionError if neither is set).
Example::
class InvoiceViewSet(ActionSerializerResolver, GenericViewSet):
action_specs = {
"list": SelectorSpec(output_serializer=InvoiceListSerializer),
"retrieve": SelectorSpec(output_serializer=InvoiceDetailSerializer),
}
Custom actions¶
service_action ¶
service_action(
spec: ServiceSpec,
*,
detail: bool = False,
methods: list[str] | None = None,
url_path: str | None = None,
url_name: str | None = None,
**action_kwargs: Any,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]
Wrap a viewset method as a service-backed custom action.
The decorated method's body is not executed — the decorator supplies
the handler. The method exists so that @service_action can attach
DRF @action metadata and pick up the action name from __name__.
Pass a :class:ServiceSpec for the service wiring. detail,
methods, url_path, url_name, and any extra **action_kwargs
are forwarded to DRF's @action.