Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sainipray/drf-fsm

Create Django FSM transitions as a endpoint with Django REST Framework
https://github.com/sainipray/drf-fsm

django django-fsm django-rest-framework fsm-field fsm-transition python3 viewsets

Last synced: about 1 month ago
JSON representation

Create Django FSM transitions as a endpoint with Django REST Framework

Awesome Lists containing this project

README

        

===============
Django FSM with Django Rest Framework.
===============

Overview
========
drf_fsm library provides an endpoint for defined each transition in models using Django FSM with Django Rest Framework library.

Features
========
This library provides endpoint for each transition of FSM and customize like:

1. Easy to define the number of FSM fields that's the endpoint you want to create automatically. default : No field.
2. Easy to define how many transitions endpoint you want to create for particular field: default: all transition of fields.
3. Easy to define serializer for each transition and field name wise: default: serializer_class of ViewSet.
4. Easy to handle response for each endpoint of transition and field, default: serializer.data .

Installation
============

- Install drf_fsm using pip::

pip install drf_fsm

- Import Mixin from drf_fsm and Use in ViewSet views of DRF::

from drf_fsm.mixins import FsmViewSetMixin

Uses with example
================

Lets Suppose a Post model that uses Django FSM

models.py::

from django.contrib.auth import get_user_model
from django.db import models
from django_fsm import transition, FSMField

User = get_user_model()

class PostStatusChoices(models.TextChoices):
Draft = 'draft', 'Draft'
Pending = 'pending', 'Pending'
Publish = 'publish', 'Publish'
Future = 'future', 'Future'
Trash = 'trash', 'Trash'

class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = FSMField('Status', max_length=20, default=PostStatusChoices.Draft,
choices=PostStatusChoices.choices, protected=True)

@transition(field=status, source='*', target=PostStatusChoices.Draft)
def draft(self):
pass

@transition(field=status, source=PostStatusChoices.Draft, target=PostStatusChoices.Pending)
def pending(self):
pass

@transition(field=status, source=PostStatusChoices.Pending, target=PostStatusChoices.Publish)
def publish(self):
pass

@transition(field=status, source=PostStatusChoices.Pending, target=PostStatusChoices.Future)
def future(self):
pass

@transition(field=status, source='*', target=PostStatusChoices.Trash)
def trash(self):
pass

We define model with 5 choices above and added 5 transition for each status in model.

Now create ViewSet for Post model

views.py::

from rest_framework.viewsets import ModelViewSet
from drf_fsm.mixins import FsmViewSetMixin
from .models import Post
from .serializers import PostSerializer

class PostViewSet(FsmViewSetMixin, ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
fsm_fields = ['status']

Here we define "status" as a FSM field, we can define multiple in list if we have multiple in single model

Connect this views to DRF router
urls.py::

from rest_framework.routers import DefaultRouter
from .views import PostViewSet

router = DefaultRouter()

router.register('post', PostViewSet, basename="post_view_set")

urlpatterns = router.urls

Finished. Cheers ✌️
------------------

Now checking Output in Swagger

.. image:: output.png
:width: 100%

😎 :),
====

Let's move to customizations:

Customizations
============

1. Define number of fields of FSM in view like::

fsm_fields = ['status', 'priority']

2. Define particular transitions for include, left will ignore for endpoints.
suppose field name is "status" and have 5 transition according above example so we can
handle which transition should include and other ignore.

So write @classmethod in viewset for override this feature::

@classmethod
def status_transitions(cls): # Here status in field name so it's dynamic based on FSM field name.
return ['trash', 'publish']

Here "trash" and "publish" transition endpoint will available for API, other will ignore from endpoints

3. Define serializer class for each transition or field name wise::

publish_status_serializer_class = PublishStatusPostSerializer # {transition}_{field_name}_serializer_class

or

status_serializer_class = StatusPostSerializer # {field_name}_serializer_class

or, default

serializer_class = PostSerializer # Default serializer class for each

Serializer class uses dynamic name for each transition if define otherwise default will use.

4. Define Response of each transition::

def publish_status_response(self, serializer): # {transition}_{field_name}_response
return {"message": "Post status updated published"}

or

def status_response(self, serializer): # {field_name}_response, but it'll show for all transition of status field
return {"message": "Post status updated"}

or, default

serializer.data

Finished Customizations
------------------------

.. image:: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png
:target: https://www.buymeacoffee.com/sainipray

License
=======

drf_fsm is an Open Source project licensed under the terms of the `MIT license `_