CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-fsm

Django friendly finite state machine support for models through FSMField and the @transition decorator.

Pending
Overview
Eval results
Files

field-types.mddocs/

Field Types and Configuration

Core FSM field types for different data storage needs and configuration options for controlling state machine behavior.

Capabilities

FSMField

CharField-based finite state machine field that stores states as string values. This is the most commonly used FSM field type, suitable for human-readable state names.

class FSMField(FSMFieldMixin, models.CharField):
    def __init__(self, 
                 default=None, 
                 protected=False, 
                 state_choices=None, 
                 max_length=50, 
                 **kwargs):
        """
        State machine field based on CharField.
        
        Parameters:
        - default: Default state value
        - protected: If True, prevents direct field modification
        - state_choices: List of (state, title, proxy_cls_ref) tuples for proxy switching
        - max_length: Maximum length for state string (default: 50)
        - **kwargs: Standard CharField parameters
        """

Usage example:

from django.db import models
from django_fsm import FSMField, transition

class Order(models.Model):
    status = FSMField(default='pending', protected=True)
    
    @transition(field=status, source='pending', target='confirmed')
    def confirm(self):
        pass

FSMIntegerField

IntegerField-based finite state machine field that stores states as integer values. Useful when states need to be represented numerically or when integrating with systems that use integer status codes.

class FSMIntegerField(FSMFieldMixin, models.IntegerField):
    def __init__(self, 
                 default=None, 
                 protected=False, 
                 state_choices=None, 
                 **kwargs):
        """
        State machine field based on IntegerField.
        
        Parameters:
        - default: Default state value (integer)
        - protected: If True, prevents direct field modification
        - state_choices: List of (state, title, proxy_cls_ref) tuples for proxy switching
        - **kwargs: Standard IntegerField parameters
        """

Usage example:

class Task(models.Model):
    STATUS_NEW = 0
    STATUS_IN_PROGRESS = 1
    STATUS_COMPLETED = 2
    
    STATUS_CHOICES = [
        (STATUS_NEW, 'New'),
        (STATUS_IN_PROGRESS, 'In Progress'),
        (STATUS_COMPLETED, 'Completed'),
    ]
    
    status = FSMIntegerField(
        default=STATUS_NEW,
        choices=STATUS_CHOICES
    )
    
    @transition(field=status, source=STATUS_NEW, target=STATUS_IN_PROGRESS)
    def start_work(self):
        pass

FSMKeyField

ForeignKey-based finite state machine field that stores states as references to related model instances. Useful when states need to be managed in a separate model with additional metadata.

class FSMKeyField(FSMFieldMixin, models.ForeignKey):
    def __init__(self, 
                 to, 
                 default=None, 
                 protected=False, 
                 state_choices=None, 
                 **kwargs):
        """
        State machine field based on ForeignKey.
        
        Parameters:
        - to: Related model class or string reference
        - default: Default state value (foreign key reference)
        - protected: If True, prevents direct field modification
        - state_choices: List of (state, title, proxy_cls_ref) tuples for proxy switching
        - **kwargs: Standard ForeignKey parameters (on_delete required)
        """

Usage example:

class WorkflowState(models.Model):
    name = models.CharField(max_length=50, primary_key=True)
    description = models.TextField()

class Document(models.Model):
    state = FSMKeyField(
        'WorkflowState', 
        default='draft',
        on_delete=models.PROTECT
    )
    
    @transition(field=state, source='draft', target='review')
    def submit_for_review(self):
        pass

FSMFieldMixin

Base mixin class that provides finite state machine functionality to Django model fields. This is the core implementation used by all FSM field types.

class FSMFieldMixin(object):
    def __init__(self, 
                 *args,
                 protected=False, 
                 state_choices=None, 
                 **kwargs):
        """
        Base FSM functionality mixin.
        
        Parameters:
        - *args: Positional arguments passed to parent field class
        - protected: If True, prevents direct field assignment
        - state_choices: List of (state, title, proxy_cls_ref) tuples
        - **kwargs: Keyword arguments passed to parent field class
        """
    
    def get_state(self, instance): ...
    def set_state(self, instance, state): ...
    def change_state(self, instance, method, *args, **kwargs): ...
    def get_all_transitions(self, instance_cls): ...

Field Configuration Options

Protected Fields

When protected=True, the field cannot be modified directly through assignment. State changes must occur through transition methods.

class BlogPost(models.Model):
    state = FSMField(default='draft', protected=True)
    
    # This will raise AttributeError
    # post.state = 'published'  # Error!
    
    # Must use transition instead
    @transition(field=state, source='draft', target='published')
    def publish(self):
        pass

State Choices with Proxy Models

The state_choices parameter allows automatic proxy model switching based on state values:

class BaseDocument(models.Model):
    state = FSMField(
        default='draft',
        state_choices=[
            ('draft', 'Draft', 'DraftDocument'),
            ('published', 'Published', 'PublishedDocument'),
        ]
    )

class DraftDocument(BaseDocument):
    class Meta:
        proxy = True
    
    def edit_content(self):
        pass

class PublishedDocument(BaseDocument):
    class Meta:
        proxy = True
    
    def unpublish(self):
        pass

# When state changes, instance class automatically switches
doc = BaseDocument.objects.create()
print(type(doc))  # <class 'BaseDocument'>

doc.state = 'draft'
print(type(doc))  # <class 'DraftDocument'>

doc.state = 'published'  
print(type(doc))  # <class 'PublishedDocument'>

Dynamic Model Methods

For each FSM field named {field_name}, django-fsm automatically adds these methods to the model:

get_all_{field_name}_transitions

def get_all_{field_name}_transitions(self):
    """
    Returns all transitions available for the field.
    
    Returns:
    Generator of Transition objects
    """

get_available_{field_name}_transitions

def get_available_{field_name}_transitions(self):
    """
    Returns transitions available from current state with conditions met.
    
    Returns:
    Generator of Transition objects
    """

get_available_user_{field_name}_transitions

def get_available_user_{field_name}_transitions(self, user):
    """
    Returns available transitions that user has permission to execute.
    
    Parameters:
    - user: User instance for permission checking
    
    Returns:
    Generator of Transition objects
    """

Usage example:

# For a field named 'status'
order = Order.objects.get(pk=1)

# Get all possible transitions
all_transitions = list(order.get_all_status_transitions())

# Get currently available transitions
available = list(order.get_available_status_transitions())

# Get transitions available to specific user
user_transitions = list(order.get_available_user_status_transitions(request.user))

Utility Functions

These functions power the dynamic model methods and can be used directly when needed:

get_available_FIELD_transitions

def get_available_FIELD_transitions(instance, field):
    """
    List of transitions available in current model state with all conditions met.
    
    Parameters:
    - instance: Model instance
    - field: FSM field instance
    
    Returns:
    Generator yielding Transition objects that are available from current state
    """

get_all_FIELD_transitions

def get_all_FIELD_transitions(instance, field):
    """
    List of all transitions available in current model state.
    
    Parameters:
    - instance: Model instance  
    - field: FSM field instance
    
    Returns:
    Generator yielding all Transition objects for the field
    """

get_available_user_FIELD_transitions

def get_available_user_FIELD_transitions(instance, user, field):
    """
    List of transitions available in current model state with all conditions 
    met and user has rights on it.
    
    Parameters:
    - instance: Model instance
    - user: User instance for permission checking
    - field: FSM field instance
    
    Returns:
    Generator yielding Transition objects available to the user
    """

Direct usage example:

from django_fsm import get_available_FIELD_transitions

class Order(models.Model):
    status = FSMField(default='pending')

def check_order_transitions(order):
    # Use utility function directly
    field = Order._meta.get_field('status')
    available = list(get_available_FIELD_transitions(order, field))
    
    for transition in available:
        print(f"Available transition: {transition.name}")

Install with Tessl CLI

npx tessl i tessl/pypi-django-fsm

docs

dynamic-states.md

exceptions.md

field-types.md

index.md

model-mixins.md

signals.md

transitions.md

visualization.md

tile.json