Skip to content

Mutations

Sync helpers

apply_input

apply_input(
    instance: Model,
    data: Any,
    *,
    field_map: dict[str, str] | None = None,
    exclude_fields: list[str] | None = None,
) -> ChangeResult

Set attributes from data onto instance without saving.

Returns a ChangeResult describing fields whose value actually changed. Useful when a service wants to inspect what the input would change before deciding whether to persist.

create_from_input

create_from_input(
    model: type[ModelT],
    data: Any,
    *,
    field_map: dict[str, str] | None = None,
    exclude_fields: list[str] | None = None,
    m2m: dict[str, Any] | None = None,
    children: Mapping[str, ChildSpec] | None = None,
    relations: Mapping[str, RelationSpec] | None = None,
    context: Mapping[str, Any] | None = None,
) -> ChangeResult[ModelT]

Build, save(), and return a fresh instance of model.

Regular fields come from data (a dataclass, dict, or object with __dict__); M2M assignments are applied post-save via the m2m kwarg, mapping attribute name to the value to set(). That argument assigns rows which already exist; writing the target rows from the payload is a ManyToManySpec in relations. Both still ship — they are different jobs — but a relation named by both is refused, since it would be written twice and keep whichever ran last.

relations maps a relation name to the spec for its kind; the nested payload is read from data[relation] and written in the order the kind dictates, not the order the map is spelled in (see RelationPhase). children is the reverse-FK alias — the same map under the name it shipped as — and a name declared in both raises. Keep the whole call inside the service's atomic block.

context is an opaque mapping forwarded verbatim into the pool of any per-child service a ChildSpec declares. This helper never reads it — it exists so per-row work downstream can see the acting caller. The default model-service factories populate it from the framework's kwargs pool automatically; a hand-written service opts in with context=kwargs.

update_from_input

update_from_input(
    instance: ModelT,
    data: Any,
    *,
    field_map: dict[str, str] | None = None,
    exclude_fields: list[str] | None = None,
    m2m: dict[str, Any] | None = None,
    update_fields: bool | list[str] = True,
    children: Mapping[str, ChildSpec] | None = None,
    relations: Mapping[str, RelationSpec] | None = None,
    context: Mapping[str, Any] | None = None,
) -> ChangeResult[ModelT]

Update instance with values from data, persisting only deltas.

By default (update_fields=True), the save call uses update_fields=<changed> to write the minimal set of columns. auto_now=True fields (e.g. updated_at) are automatically added to that list so they are refreshed alongside the mutation. Pass False to perform a full save, or an explicit list to control exactly which columns are written (no auto-injection in that case).

m2m assigns many-to-many rows that already exist; ManyToManySpec in relations writes the target rows from the payload instead. A relation named by both is refused rather than written twice.

relations maps a relation name to the spec for its kind (children is the reverse-FK alias). The nested payload from data[relation] is reconciled with what is already there — create / update / orphan-remove per the spec — and a relation the input omits is left untouched. Kinds are written in the order their class dictates, so a forward foreign key is resolved before this instance is saved and the assignment rides the same diff and update_fields path as any other column. Keep the call inside the service's atomic block.

A relation that was written stays readable off the returned instance. The one-row kinds resolve their row by re-querying, so the parent's cached related object is replaced with the row that was written — and dropped where the write removed it — rather than left holding pre-write values.

context is an opaque mapping forwarded verbatim into the pool of any per-child service a ChildSpec declares; this helper never reads it. See create_from_input.

Async helpers

acreate_from_input async

acreate_from_input(
    model: type[ModelT],
    data: Any,
    *,
    field_map: dict[str, str] | None = None,
    exclude_fields: list[str] | None = None,
    m2m: dict[str, Any] | None = None,
    children: Mapping[str, ChildSpec] | None = None,
    relations: Mapping[str, RelationSpec] | None = None,
    context: Mapping[str, Any] | None = None,
) -> ChangeResult[ModelT]

Async sibling of create_from_input using asave()/aset().

aupdate_from_input async

aupdate_from_input(
    instance: ModelT,
    data: Any,
    *,
    field_map: dict[str, str] | None = None,
    exclude_fields: list[str] | None = None,
    m2m: dict[str, Any] | None = None,
    update_fields: bool | list[str] = True,
    children: Mapping[str, ChildSpec] | None = None,
    relations: Mapping[str, RelationSpec] | None = None,
    context: Mapping[str, Any] | None = None,
) -> ChangeResult[ModelT]

Async sibling of update_from_input using asave()/aset().