djangorestframework-services¶
A service / selector layer for Django REST Framework.
DRF's default mode for mutating endpoints is "the serializer is the business
logic". That's fine for thin CRUD, but it falls apart the moment you need
to compose with an external system, fan out side effects, or write logic
that doesn't belong on a model. djangorestframework-services keeps DRF's
routing, validation, and serialization for what they're good at, and gives
you a precise, well-typed seam for the bits in the middle.
What you get¶
- Services — plain callables. The library does not define a
Servicebase class or prescribe a signature. - Selectors — plain callables that override
get_queryset()/get_object(). Filter backends, pagination, and serialization stay vanilla DRF. - Mutation helpers —
create_from_input,update_from_input,apply_input(and async siblings) with change tracking, no surprises. - Sync and async services and selectors, transparently dispatched.
- Atomic by default, opt-out per spec.
- Framework-agnostic exceptions — services don't import from DRF.
- Typed end-to-end — generic
ServiceSpec[InputT, ResultT]plus lenient and strict Protocols that catch signature drift at type-check time, with fail-fast validation atas_view(). See Typing.
When to use this¶
Reach for it when an endpoint:
- coordinates more than one model write
- talks to an external system (payments, email, queue)
- has business rules that don't belong on a model or in a serializer
- needs to differ in input shape vs. output shape (computed fields, hidden columns, denormalised joins)
- needs to mix sync and async paths
Skip it when an endpoint is "serialize → save → respond". DRF's
ModelSerializer already does that well; this library is for the cases
where it doesn't.
Install¶
That brings in djangorestframework-dataclasses automatically — it's
the recommended way to wire dataclass-shaped inputs and outputs. Plain
Serializer / ModelSerializer work everywhere too.
Where to next¶
- Quickstart — a
POST /authors/endpoint, end to end. - Concepts — the three building blocks (service, selector, view) and how dispatch works.
- Mutation helpers —
create_from_input,update_from_input,apply_input, and theChangeResultthey return. - Typing — lenient and strict Protocols, per-spec
kwargs=providers, fail-fastas_view()validation. - Errors & atomic — framework-agnostic exceptions and the transaction model.
- Async — when and how to use
async defservices. - Recipes — task-shaped how-tos.
- Reference — autodocumented public API.
Compatibility¶
| Axis | Range |
|---|---|
| Python | 3.10 – 3.14 |
| Django | 4.2, 5.0, 5.1, 5.2, 6.0 |
| DRF | ≥ 3.14 |
CI runs the full Python × Django matrix with 100% coverage gating.