Django FSM-2

4.2.4 · active · verified Thu Apr 16

Django FSM-2 is an active, maintained fork of the original `django-fsm` library, providing declarative finite state machine support for Django models. It enables developers to define state fields and transitions using decorators, centralizing an object's lifecycle logic. Currently at version 4.2.4, it aims for regular updates and planned typing support.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates defining a Django model with an FSMField and several state transitions. The `FSMModelMixin` is inherited, and `transition` decorators specify valid state changes. The example also shows how to check if a transition is allowed using `can_proceed` before executing it and saving the model instance to persist the state change to the database.

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

class BlogPost(FSMModelMixin, models.Model):
    class State(models.TextChoices):
        NEW = "new", "New"
        DRAFT = "draft", "Draft"
        PUBLISHED = "published", "Published"
        ARCHIVED = "archived", "Archived"

    title = models.CharField(max_length=255)
    state = FSMField(default=State.NEW, protected=True)

    @transition(field=state, source=State.NEW, target=State.DRAFT)
    def create_draft(self):
        print(f"Transitioning from {self.state} to {self.State.DRAFT}")

    @transition(field=state, source=State.DRAFT, target=State.PUBLISHED)
    def publish(self):
        print(f"Transitioning from {self.state} to {self.State.PUBLISHED}")

    @transition(field=state, source='*', target=State.ARCHIVED)
    def archive(self):
        print(f"Transitioning from {self.state} to {self.State.ARCHIVED}")

    def __str__(self):
        return f"{self.title} ({self.state})"

# Example Usage (assuming a Django environment and database):
# from .models import BlogPost, can_proceed # assuming this is in app.models
#
# post = BlogPost.objects.create(title='My First Post')
# print(post) # My First Post (new)
#
# if can_proceed(post.create_draft):
#     post.create_draft()
#     post.save()
# print(post) # My First Post (draft)
#
# if can_proceed(post.publish):
#     post.publish()
#     post.save()
# print(post) # My First Post (published)
#
# # Attempting an invalid transition
# if can_proceed(post.create_draft):
#     print("Should not be able to draft from published state")
# else:
#     print(f"Cannot transition from {post.state} to draft")
#
# if can_proceed(post.archive):
#     post.archive()
#     post.save()
# print(post) # My First Post (archived)

view raw JSON →