{"id":22188424,"url":"https://github.com/sainipray/drf-fsm","last_synced_at":"2025-07-26T20:32:02.925Z","repository":{"id":57424065,"uuid":"413120963","full_name":"sainipray/drf-fsm","owner":"sainipray","description":"Create Django FSM transitions as a endpoint with Django REST Framework","archived":false,"fork":false,"pushed_at":"2022-06-17T06:51:19.000Z","size":493,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-15T21:49:54.037Z","etag":null,"topics":["django","django-fsm","django-rest-framework","fsm-field","fsm-transition","python3","viewsets"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sainipray.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-03T15:43:14.000Z","updated_at":"2023-10-10T08:17:29.000Z","dependencies_parsed_at":"2022-09-14T07:52:54.112Z","dependency_job_id":null,"html_url":"https://github.com/sainipray/drf-fsm","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sainipray%2Fdrf-fsm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sainipray%2Fdrf-fsm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sainipray%2Fdrf-fsm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sainipray%2Fdrf-fsm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sainipray","download_url":"https://codeload.github.com/sainipray/drf-fsm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227715611,"owners_count":17808734,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-fsm","django-rest-framework","fsm-field","fsm-transition","python3","viewsets"],"created_at":"2024-12-02T11:10:27.747Z","updated_at":"2024-12-02T11:10:28.323Z","avatar_url":"https://github.com/sainipray.png","language":"Python","funding_links":["https://www.buymeacoffee.com/sainipray"],"categories":[],"sub_categories":[],"readme":"===============\nDjango FSM with Django Rest Framework.\n===============\n\nOverview\n========\ndrf_fsm library provides an endpoint for defined each transition in models using Django FSM with Django Rest Framework library.\n\n\nFeatures\n========\nThis library provides endpoint for each transition of FSM and customize like:\n\n1. Easy to define the number of FSM fields that's the endpoint you want to create automatically. default : No field.\n2. Easy to define how many transitions endpoint you want to create for particular field: default: all transition of fields.\n3. Easy to define serializer for each transition and field name wise: default: serializer_class of ViewSet.\n4. Easy to handle response for each endpoint of transition and field, default: serializer.data .\n\nInstallation\n============\n\n- Install drf_fsm using pip::\n\n    pip install drf_fsm\n\n- Import Mixin from drf_fsm and Use in ViewSet views of DRF::\n\n    from drf_fsm.mixins import FsmViewSetMixin\n\n\nUses with example\n================\n\nLets Suppose a Post model that uses Django FSM\n\nmodels.py::\n\n    from django.contrib.auth import get_user_model\n    from django.db import models\n    from django_fsm import transition, FSMField\n\n    User = get_user_model()\n\n\n    class PostStatusChoices(models.TextChoices):\n        Draft = 'draft', 'Draft'\n        Pending = 'pending', 'Pending'\n        Publish = 'publish', 'Publish'\n        Future = 'future', 'Future'\n        Trash = 'trash', 'Trash'\n\n\n    class Post(models.Model):\n        title = models.CharField(max_length=200, unique=True)\n        slug = models.SlugField(max_length=200, unique=True)\n        author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')\n        updated_on = models.DateTimeField(auto_now=True)\n        content = models.TextField()\n        created_on = models.DateTimeField(auto_now_add=True)\n        status = FSMField('Status', max_length=20, default=PostStatusChoices.Draft,\n                          choices=PostStatusChoices.choices, protected=True)\n\n        @transition(field=status, source='*', target=PostStatusChoices.Draft)\n        def draft(self):\n            pass\n\n        @transition(field=status, source=PostStatusChoices.Draft, target=PostStatusChoices.Pending)\n        def pending(self):\n            pass\n\n        @transition(field=status, source=PostStatusChoices.Pending, target=PostStatusChoices.Publish)\n        def publish(self):\n            pass\n\n        @transition(field=status, source=PostStatusChoices.Pending, target=PostStatusChoices.Future)\n        def future(self):\n            pass\n\n        @transition(field=status, source='*', target=PostStatusChoices.Trash)\n        def trash(self):\n            pass\n\n\n\n\nWe define model with 5 choices above and added 5 transition for each status in model.\n\nNow create ViewSet for Post model\n\nviews.py::\n\n    from rest_framework.viewsets import ModelViewSet\n    from drf_fsm.mixins import FsmViewSetMixin\n    from .models import Post\n    from .serializers import PostSerializer\n\n\n    class PostViewSet(FsmViewSetMixin, ModelViewSet):\n        queryset = Post.objects.all()\n        serializer_class = PostSerializer\n        fsm_fields = ['status']\n\n\nHere we define \"status\" as a FSM field, we can define multiple in list if we have multiple in single model\n\nConnect this views to DRF router\nurls.py::\n\n    from rest_framework.routers import DefaultRouter\n    from .views import PostViewSet\n\n    router = DefaultRouter()\n\n    router.register('post', PostViewSet, basename=\"post_view_set\")\n\n    urlpatterns = router.urls\n\n\nFinished. Cheers ✌️\n------------------\n\nNow checking Output in Swagger\n\n.. image:: output.png\n   :width: 100%\n\n\n😎 :),\n====\n\nLet's move to customizations:\n\nCustomizations\n============\n\n1. Define number of fields of FSM in view like::\n\n    fsm_fields = ['status', 'priority']\n\n2. Define particular transitions for include, left will ignore for endpoints.\n   suppose field name is \"status\" and have 5 transition according above example so we can\n   handle which transition should include and other ignore.\n\n   So write @classmethod in viewset for override this feature::\n\n    @classmethod\n    def status_transitions(cls):  # Here status in field name so it's dynamic based on FSM field name.\n        return ['trash', 'publish']\n\nHere \"trash\" and \"publish\" transition endpoint will available for API, other will ignore from endpoints\n\n3. Define serializer class for each transition or field name wise::\n\n    publish_status_serializer_class = PublishStatusPostSerializer # {transition}_{field_name}_serializer_class\n\n    or\n\n    status_serializer_class = StatusPostSerializer  # {field_name}_serializer_class\n\n    or, default\n\n    serializer_class = PostSerializer  # Default serializer class for each\n\nSerializer class uses dynamic name for each transition if define otherwise default will use.\n\n4. Define Response of each transition::\n\n        def publish_status_response(self, serializer): # {transition}_{field_name}_response\n            return {\"message\": \"Post status updated published\"}\n\n        or\n\n        def status_response(self, serializer): # {field_name}_response, but it'll show for all transition of status field\n            return {\"message\": \"Post status updated\"}\n\n        or, default\n\n        serializer.data\n\n\n\n\nFinished Customizations\n------------------------\n\n\n.. image:: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png\n   :target: https://www.buymeacoffee.com/sainipray\n\nLicense\n=======\n\ndrf_fsm is an Open Source project licensed under the terms of the `MIT license \u003chttps://github.com/sainipray/drf-fsm/blob/main/LICENSE\u003e`_\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsainipray%2Fdrf-fsm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsainipray%2Fdrf-fsm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsainipray%2Fdrf-fsm/lists"}