Registry / database / django-fsm-2

django-fsm-2

JSON →
library4.2.4pypypi✓ verified 87d ago

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.

pip install django-fsm-2
INSTALL
IMPORT
SIG · DJANGO-FSM-2
D
django-fsm-2
databasepythonv4.2.4
Install
3.5s avg
Import
579ms
Disk
66MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v4.2.4 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.614s · 66.6MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 3.5s · import 0.544s · 67MB
66MB installed
● package 66MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

FSMField
from django_fsm import FSMField
from django_fsm.db.fields import FSMField
The field types are directly available under `django_fsm` in modern versions, not `django_fsm.db.fields`.
FSMModelMixin
from django_fsm import FSMModelMixin
Required for `FSMField` to function correctly on models.
transition
from django_fsm import transition
Decorator for defining state transitions on model methods.
can_proceed
from django_fsm import can_proceed
Utility function to check if a transition is currently allowed.
FSMAdminMixin
from django_fsm.admin import FSMAdminMixin
from fsm_admin.mixins import FSMTransitionMixin
While `FSMTransitionMixin` exists in `django-fsm-2-admin`, `FSMAdminMixin` is the built-in option if `django-fsm-2-admin` is not used. Import paths differ between the two projects.

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)
Debug
Known issues
breakingVersion 4.0.0 of `django-fsm-2` removed support for Django 3.2, 4.0, and 4.1. It added support for Django 5.1. Projects on these older Django versions should stick to `django-fsm-2 < 4.0.0` or upgrade their Django version.
fix
Upgrade Django to a supported version (e.g., 5.1+) or pin `django-fsm-2` to a version prior to 4.0.0 (e.g., `django-fsm-2<4.0.0`).
affects: >=4.0.0
gotchaAttempting to directly assign a new value to an `FSMField` (e.g., `instance.state = 'new_state'`) will often fail with an `AttributeError` if the field is `protected=True` (which is often the default or desired behavior). State changes *must* occur via methods decorated with `@transition`.
fix
Always use the methods decorated with `@transition` to change the state of an FSM-managed field, e.g., `instance.transition_method()`.
affects: All
gotchaAfter a successful transition method call, the model's state is updated in memory, but it is *not* automatically persisted to the database. You must explicitly call `instance.save()` to commit the state change.
fix
Ensure `instance.save()` is called immediately after a successful transition method execution to persist the state change. For concurrent environments, consider using `django_fsm.ConcurrentTransitionMixin` within `django.db.transaction.atomic()` blocks.
affects: All
breakingThe original `django-fsm` project was archived and later revived as `viewflow.fsm` (version 3.0.0+), introducing an entirely new and incompatible API. While `django-fsm-2` aims to be a drop-in replacement for *older* `django-fsm` versions (pre-archival), migrating from `viewflow.fsm` (i.e., `django-fsm >= 3.0.0`) to `django-fsm-2` is not a simple switch.
fix
If migrating from `django-fsm` before its archival, `django-fsm-2` is a drop-in replacement. If migrating from the *new* `viewflow.fsm` (aka `django-fsm` 3.0.0+), expect significant API refactoring, as `viewflow.fsm` uses a different `State` class and transition paradigm.
affects: Users of `django-fsm >= 3.0.0` (which is `viewflow.fsm`)
Errors
Common errors & fixes
AttributeError: can't set attribute 'state' (or similar with your FSMField name)
Attempting to directly assign a new value to an FSMField, which is protected against direct modification.
fix
Use a method decorated with `@transition` to change the state. For example, if your field is `state` and you have a `publish()` method: `my_model_instance.publish()`.
TransitionNotAllowed
An attempt was made to execute a transition that is not permitted by the defined state machine rules (e.g., source state does not match, or target state is unreachable from the current state).
fix
Ensure the current state of the model instance is a valid `source` for the desired transition. Check the `@transition` decorator's `source` and `target` parameters. Use `can_proceed(instance.transition_method)` to check validity before calling.
NameError: name 'my_state_constant' is not defined
This usually happens when state names in `source` or `target` parameters of the `@transition` decorator are used as unquoted variables instead of string literals or properly imported constants (e.g., from `models.TextChoices`).
fix
Ensure state names are either enclosed in quotes (e.g., `source='new'`) or correctly reference an imported/defined constant (e.g., `source=BlogPost.State.NEW`).
Upgrade
Version history
4.2.4latest on PyPI · released Mar 16, 2026
Audit
Dependencies
DjangorequiredCore framework dependency, specific versions supported.
django-fsm-logoptionalProvides persistence and logging of FSM transitions.
django-fsm-2-adminoptionalIntegrates FSM transitions into the Django Admin interface.
graphvizoptionalRequired for drawing state transition diagrams.
Agent activity
8 hits · last 30 days
node
8
Resources
django-fsm-2 — pip install django-fsm-2 · libregistry