You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A destroy/DELETEServiceSpec with a custom success_status whose
service returns None now renders an empty body at the configured
status. Previously the update-in-place fallback misfired (it keyed off
"status ≠ 204" as a proxy for "this is an update"), surfacing the stale
post-delete instance as the response body — which then failed to serialize.
The fallback is now driven by an explicit update-vs-destroy intent flag.
No-output mutations (no output_selector_spec) whose service returns None
now always render an empty body instead of attempting to serialize the raw
in-memory model instance. This makes no-input/no-output update and destroy services work as expected. An explicitly-set spec.success_status
is honored for the empty-body response; otherwise it falls back to 204. A
selector that returns None still renders 204 (its result is
authoritative).
Changed
The internal "is this a Django QuerySet?" check used by the selector and
mutation-output dispatch paths is now a single is_queryset() predicate
(isinstance against QuerySet/Manager) instead of three scattered hasattr(..., "first") / hasattr(..., "annotate") duck-typing checks.
More precise (a domain object that merely exposes .first() is no longer
mistaken for a queryset) and self-documenting. No public API change.
Documentation
Clarified that LIST selectors may return any iterable (plain list, tuple, hand-built dataclass sequences, …), not only a
QuerySet. The only constraints are inherent: the queryset-only shaping
fields cannot be combined with a non-QuerySet return, and lazy
generators do not survive slicing/counting paginators. See the queryset-shaping recipe.