django-fsm
Django-friendly finite state machine support.
django-fsm adds simple, declarative state management for Django models and plain Python objects.
Define states and transitions explicitly instead of spreading state assignments across views and models. Transitions check source states and business conditions before running a method. Permissions are checked explicitly with has_transition_perm() or by UI/REST integrations.
Installation
python -m pip install django-fsm
For plain Python classes, no other dependencies are required. To use with Django models, make sure Django is installed or specify the extra:
python -m pip install 'django-fsm[django]'
Quick start
Add an FSMField to your Django model and mark transition methods with the @transition decorator:
from django.db import models
from django_fsm import FSMField, transition, can_proceed
class BlogPost(models.Model):
state = FSMField(default='draft', protected=True)
@transition(field=state, source='draft', target='published')
def publish(self):
"""Side-effects when publishing a post (e.g. notify users, update cache)."""
The protected=True option prevents direct state modification:
post = BlogPost()
post.state = 'published' # Raises AttributeError
To invoke a transition and persist the change:
post = BlogPost.objects.get(pk=post_id)
if can_proceed(post.publish):
post.publish()
post.save()
Conditions and Permissions
Conditions
Use the conditions argument to enforce rules before a transition is allowed. Conditions are callables that take the model instance and return a boolean:
def can_publish(instance):
return bool(instance.title and instance.body)
class BlogPost(models.Model):
state = FSMField(default='draft')
@transition(field=state, source='draft', target='published', conditions=[can_publish])
def publish(self):
pass
Permissions
You can guard transitions with permissions and verify them using has_transition_perm:
from django_fsm import transition, has_transition_perm
class BlogPost(models.Model):
state = FSMField(default='draft')
@transition(field=state, source='draft', target='published', permission='blog.can_publish')
def publish(self):
pass
A direct call such as post.publish() does not check user permissions. Use has_transition_perm() before calling it, as below, or use an integration that performs the check.
In your view:
if not has_transition_perm(post.publish, request.user):
raise PermissionDenied
post.publish()
post.save()
Dynamic Targets
When the target state depends on runtime logic or method results:
RETURN_VALUE(*allowed_states) selects the target from the method’s return value:
from django_fsm import FSMField, RETURN_VALUE, transition
class Task(models.Model):
status = FSMField(default='pending')
@transition(field=status, source='pending', target=RETURN_VALUE('approved', 'rejected'))
def review(self, score):
return 'approved' if score >= 80 else 'rejected'
GET_STATE(func, states=[...]) calculates the target state before the transition runs, based on the instance and method arguments.
Plain Python State Machines
State also works with plain Python classes without Django database models or settings:
from django_fsm import State
class Review:
state = State(states=None, default='draft')
@state.transition(source='draft', target='published')
def publish(self):
pass
review = Review()
review.publish()
assert review.state == 'published'
Upgrading from django-fsm 3.x
Version 5.0 uses the Viewflow transition engine. Ordinary targets are now applied before the method body runs; django-fsm 3.x applied them after the method returned. Code that reads self.state inside a transition therefore observes the target state in 5.0.
GET_STATE also computes and applies its target before the method runs. RETURN_VALUE applies the target after the method returns.
If the method raises, the adapter restores the source state in memory, or applies on_error when specified. This does not undo database writes or external side effects performed by the method. Use transaction.atomic() around the transition and save() when those database writes must roll back together.
Viewflow Pro Integrations
django-fsm integrates out of the box with Viewflow Pro and Django REST Framework:
django_fsm.admin.FlowAdminMixin: Viewflow Admin integration for state workflows.
django_fsm.viewset.FlowViewsMixin: Viewflow Viewset workflows.
django_fsm.rest.FlowRESTMixin: Optional Django REST Framework viewset integration (requires django-fsm[rest]).
Documentation & Contributing
Full documentation: https://docs.viewflow.io/fsm/index.html
Contributing & development instructions: see CONTRIBUTING.rst
License
Django FSM is licensed under AGPL-3.0-or-later with the viewflow-library-exception. See LICENSE and LICENSE_EXCEPTION for details.
Metadata
Release files for django-fsm 5.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| django_fsm-5.0.1.tar.gz | 74.3 kB | Without provenance | Details for django_fsm-5.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| django_fsm-5.0.1-py3-none-any.whl | Python 3 | none | any | Details for django_fsm-5.0.1-py3-none-any.whl |
Total release size: 120.5 kB
Release files / django_fsm-5.0.1.tar.gz
| Download URL | django_fsm-5.0.1.tar.gz |
|---|---|
| Size | 74.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
afffa8aa8dcd5cb234451e56562392b3bded2838b04913f038230cd15c2c9b76
|
|
BLAKE2b-256 checksum How to use checksums |
b7ad8766c42fa281b433d5ae8de5445a693796a5dc285d724047ea63003d431c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / django_fsm-5.0.1-py3-none-any.whl
| Download URL | django_fsm-5.0.1-py3-none-any.whl |
|---|---|
| Size | 46.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5e8673f9ac50db2df8e2234608541641ea1bf6364f4296269ef36b88a78a1daf
|
|
BLAKE2b-256 checksum How to use checksums |
eb0b91b9da5e98de5617d273352070f2d031c2691c24ae51386057ba54a0c41b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Security for django-fsm 5.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.