Django FSM

3.0.1 · deprecated · verified Mon Apr 13

Django FSM (Finite State Machine) provides declarative state management for Django models. It allows defining states and transitions using decorators, ensuring state changes adhere to predefined rules. The standalone `django-fsm` library, currently at version 3.0.1, is deprecated; its functionality has been integrated into `viewflow.fsm` since version 3.0.0. The original library will no longer receive updates.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates defining states with `FSMField` and transitions with the `@transition` decorator for a `BlogPost` model. It highlights basic state transitions and the use of `protected=True` to enforce transitions via methods only. Note that for versions 3.0.0 and above, the functionality has migrated to `viewflow.fsm`.

import os
import django
from enum import Enum
from django.db import models
from django_fsm import FSMField, transition

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project_name.settings') # Replace with actual project settings if needed
django.setup()

class BlogPost(models.Model):
    class BlogState(models.TextChoices):
        DRAFT = "draft", "Draft"
        REVIEW = "review", "Under Review"
        PUBLISHED = "published", "Published"
        ARCHIVED = "archived", "Archived"

    state = FSMField(choices=BlogState.choices, default=BlogState.DRAFT, protected=True)
    title = models.CharField(max_length=255)
    content = models.TextField()

    @transition(field=state, source=BlogState.DRAFT, target=BlogState.REVIEW)
    def submit_for_review(self):
        print(f"Blog post '{self.title}' submitted for review.")

    @transition(field=state, source=BlogState.REVIEW, target=BlogState.PUBLISHED)
    def publish(self):
        print(f"Blog post '{self.title}' published!")

    @transition(field=state, source=[BlogState.DRAFT, BlogState.REVIEW, BlogState.PUBLISHED], target=BlogState.ARCHIVED)
    def archive(self):
        print(f"Blog post '{self.title}' archived.")

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

# Example Usage (assuming a Django environment is set up and models are synced)
# For a real application, replace this with actual model creation/retrieval.
# try:
#     blog_post = BlogPost.objects.create(title="My First Post", content="Lorem ipsum...")
#     print(blog_post)

#     if can_proceed(blog_post.submit_for_review):
#         blog_post.submit_for_review()
#         blog_post.save()
#         print(blog_post)

#     if can_proceed(blog_post.publish):
#         blog_post.publish()
#         blog_post.save()
#         print(blog_post)

#     if can_proceed(blog_post.archive):
#         blog_post.archive()
#         blog_post.save()
#         print(blog_post)

#     # This would fail if protected=True and not using a transition method
#     # blog_post.state = BlogPost.BlogState.DRAFT
#     # blog_post.save()

# except Exception as e:
#     print(f"An error occurred: {e}")

view raw JSON →