API

class viewflow.fsm.TransitionNotAllowed

Exception raised when a state transition is not permitted.

Base class for NoTransition and TransitionConditionsUnmet. Catch this to handle any transition failure, or catch a subclass to distinguish why the transition was refused.

class viewflow.fsm.NoTransition(label: str, state: Any)

Raised when the current state has no transition registered for the call.

Variables
  • label – human-readable label of the transition method that was called.
  • state – the state the instance was in when the call was made.
class viewflow.fsm.TransitionConditionsUnmet(transition: Transition, failed_condition: ThisObject | Callable[[T], bool], unmet_message: str = '')

Raised when a transition’s conditions callback returned false.

Variables
  • transition – the Transition that was attempted.
  • failed_condition – the first condition callable that returned false.
  • unmet_message – human-readable reason from a State.CONDITION result, or "" if the condition just returned a falsy value.
class viewflow.fsm.InvalidTargetState(transition: Transition, target: Any, allowed_states: Iterable[Any])

Raised when a State.RETURN_VALUE/State.GET_STATE target resolves to a state outside its declared allowed states.

Variables
  • transition – the Transition that was attempted.
  • target – the resolved (invalid) state value.
  • allowed_states – the declared allowed states.
class viewflow.fsm.State(states: Any, default: Any = None)

State slot field.

@transition(self, source: Any, target: Any | None = DEFAULT, label: str | None = None, conditions: List[ThisObject | Callable[[T], bool]] | None = None, permission: ThisObject | Callable[[T, Any], bool] | None = DEFAULT, custom: Dict | None = None) Any

Decorator to mark a method as a state transition.

ANY

alias of ANY

class CONDITION(is_true: bool, unmet: str = '')

Boolean-like object to return value accompanied with a message from fsm conditions.

class RETURN_VALUE(*allowed_states: Any)

target=State.RETURN_VALUE(*allowed_states) – the transition target is the method’s own return value, resolved only after it successfully returns (side effects in the method body already happened by then; there’s no way to know the target any sooner).

allowed_states, if given, restricts and documents the possible targets: chart() draws an edge for each, and a return value outside the set raises InvalidTargetState instead of silently landing on an undeclared state. Omit it to allow any return value.

class GET_STATE(func: Callable[[...], Any], states: List[Any] | None = None)

target=State.GET_STATE(func, states=[...]) – the transition target is computed by func(instance, *args, **kwargs) from the call’s own arguments, resolved before the transition method runs – so, unlike State.RETURN_VALUE, the method body already observes the new state, and nothing runs if the computed target turns out invalid.

states, if given, restricts and documents the possible targets: chart() draws an edge for each, and a computed target outside the set raises InvalidTargetState. Omit it to allow any target func returns.

class viewflow.fsm.FlowAdminMixin

A Mixin for providing Finite State Machine (FSM) management support in Django admin.

class viewflow.fsm.rest.FlowRESTMixin

ModelViewSet mixing exposes transition methods.

viewflow.fsm.chart(flow_state: StateDescriptor, exclude_guards=True)

Draws a directed graph (digraph) of the state transitions defined in the given flow_state.

Args:
flow_state (StateDescriptor): The state descriptor object. exclude_guards (bool): Whether to exclude transitions with no target state.
Returns:
str: A string representation of the digraph in the DOT language.

The function uses the flow_state object to extract the transitions and the states involved. It then generates a DOT language string, which can be used with tools like Graphviz to produce an image of the graph.

A State.RETURN_VALUE/State.GET_STATE target charts one edge per declared allowed state; if none are declared, the transition is charted with no outgoing edge, since its real target is only known at runtime.

class viewflow.fsm.FSMField(*args: Any, protected: bool = False, enforce_initial: bool = False, **kwargs: Any)

A CharField whose value only changes through @transition-guarded methods – a same-column drop-in for django-fsm’s FSMField.

protected (default False, matching django-fsm): once True, direct assignment (instance.state = x) raises AttributeError after the instance’s first value is set (by Model.__init__/loading from the database) – transitions still work, since they write through State.set(), not attribute assignment. Note this also blocks a plain instance.refresh_from_db() re-assigning the field; there is no workaround for that yet, so only opt in if you don’t rely on it.

enforce_initial (default False): once True, raises NonInitialStateOnCreate from pre_save if a new row (add) would be inserted with a value other than the field’s default – closing the gap where Model.objects.create(state=DONE) bypasses every transition. Does not cover bulk_create() or raw SQL, which skip pre_save entirely.

Both default to False so porting from django-fsm is a same-behavior import swap; opt into either (or both) for viewflow’s stricter guarantees once ported code is running.

viewflow.fsm.transition(field: FSMField, source: Any, target: Any | None = DEFAULT, **kwargs: Any) Any

django-fsm-compatible decorator: @transition(field=state, source=..., target=...).

Thin wrapper over field.transition(...) for code ported from django-fsm, where the field object is passed explicitly rather than calling .transition() on it directly.

class viewflow.fsm.NonInitialStateOnCreate(field: FSMField, value: Any)

Raised creating a new row through FSMField(enforce_initial=True) with a value other than the field’s declared default.

Variables
  • field – the FSMField involved.
  • value – the rejected value.