Skip to main content

How Transitions Work

Transition as a Directed Graph

Statuses are nodes. Transitions are the directed edges between them. A record can only move along an explicitly defined edge — no implicit or free-form status changes.

draft ──submit──▶ pending ──approve──▶ active

reject


rejected ──reopen──▶ draft

Transitions

This means:

  • A pending record cannot jump directly to active unless pending → active is defined
  • You can define multiple outgoing transitions from one status (branching)
  • You can define transitions that go backwards (rollback paths)

What Happens During a Transition

  1. User clicks the transition button in the UI
  2. If a confirmation_message is set — confirmation dialog is shown
  3. If a form is set — form drawer opens; user fills it in and submits
  4. <name>_condition() is called — if it returns False, the transition is blocked
  5. The record's status is updated to the to status
  6. A WorkflowTransaction record is created (audit log)
  7. <name>_done() is called — post-transition logic runs

Transition Types

TypeHow triggeredform keyis_manual
SimpleUser clicks button, confirmsNot setTrue (default)
Form-basedUser fills in a form drawerSet to a form classTrue (default)
SystemCode only — not shown in UIOptionalFalse

Audit Trail

Every transition automatically creates a WorkflowTransaction record containing:

  • Which object transitioned
  • Which transition was executed
  • Who triggered it (request.user)
  • Timestamp
  • Any form data captured

This gives you a complete history of every status change for every record.

Transition Visibility in the UI

The frontend (WorkflowStatus component) shows only transitions that:

  1. Start from the record's current status (from matches current status)
  2. The current user's role is in roles (or roles is not set)
  3. The _condition method returns True
  4. is_manual is not False