Skip to main content

Conditions & Done Methods

Two optional method types give you control over every transition: condition methods gate whether a transition can run, and done methods execute logic after one completes.

Condition Methods

A condition method is called before a transition executes. If it returns False, the transition is blocked and the button is hidden (or an error is shown).

Naming: <transition_name>_condition

def submit_condition(self, request, object_instance, **kwargs):
"""Check if the record is ready to submit."""
if not object_instance.name:
return False, "Name is required before submitting"
if not object_instance.email:
return False, "Email is required before submitting"
return True, "Ready to submit"

Parameters

ParameterDescription
requestThe Django HttpRequest object
object_instanceThe model record being transitioned
**kwargsAdditional keyword arguments

Return Value

Return a tuple (bool, str):

  • True, "message" — transition is allowed
  • False, "reason" — transition is blocked; reason shown to user

Done Methods

A done method runs after a transition completes successfully. Use it to update metadata, send notifications, trigger async tasks, or any post-transition logic.

Naming: <transition_name>_done

def approve_done(self, request, object_instance, transaction_obj):
"""Runs after the 'approve' transition completes."""
from django.utils import timezone

# Update metadata
object_instance.approved_at = timezone.now()
object_instance.approved_by = request.user
object_instance.save() # don't forget to save!

# Send notification
send_approval_notification(object_instance)

Parameters

ParameterDescription
requestThe Django HttpRequest object
object_instanceThe model record that was transitioned
transaction_objThe WorkflowTransaction record created for this transition

:::tip Always call .save() If you modify object_instance in a done method, always call object_instance.save() — it is not auto-saved. :::

Full Example

class OrderWorkflow(WorkflowBase):

status_transitions = [
{
"name": "submit",
"display_name": "Submit",
"from": "draft",
"to": "pending",
"confirmation_message": "Submit this order for approval?",
},
{
"name": "approve",
"display_name": "Approve",
"from": "pending",
"to": "active",
"roles": ["Manager"],
"form": ApprovalForm,
},
{
"name": "reject",
"display_name": "Reject",
"from": "pending",
"to": "rejected",
"roles": ["Manager"],
},
]

def submit_condition(self, request, object_instance, **kwargs):
if not object_instance.line_items.exists():
return False, "Order must have at least one line item"
return True, "Ready to submit"

def approve_done(self, request, object_instance, transaction_obj):
from django.utils import timezone
object_instance.approved_at = timezone.now()
object_instance.approved_by = request.user
object_instance.save()
notify_order_approved(object_instance)

def reject_done(self, request, object_instance, transaction_obj):
from django.utils import timezone
object_instance.rejected_at = timezone.now()
object_instance.save()
notify_order_rejected(object_instance)

class Meta:
model = Order
on_create_status = "draft"
statuses = {
"draft": {"color": "#717680", "label": "Draft"},
"pending": {"color": "#F59E0B", "label": "Pending"},
"active": {"color": "#12B76A", "label": "Active"},
"rejected":{"color": "#F04438", "label": "Rejected"},
}