Você, desenvolvedor, já se deparou com cenários específicos em que você precisa controlar um fluxo de informações, mas, suportando diversos status, com diversos efeitos colaterais diferentes, entre cada mudança desses status?
Criar e manter este tipo de estrutura, manualmente, é bem complicado. Formalmente, este tipo de estrutura é chamada de máquina de estado finita ou finite state machines e para os íntimos, FSM.
Inspirados em outros pacotes disponíveis para o Django, construímos nosso próprio gerenciador de máquinas de estados. Este é mais um pacote open-source que disponibilizamos para a comunidade.
Aplicações das FSM
As aplicações das FSMs são diversas. Elas podem controlar como compoenentes internos de uma aplicação reagem a estímulos externos (usuário informa determinada informação) ou mesmo serem editadas pelo próprio usuário. Um exemplo disso são os famigerados BPM (Bussiness Process Management**) onde os próprios usuários definem até certo ponto, o fluxo da informação e por quais verificações esta deve passar antes de permitir a troca de um estado para outro.
Outro exemplo interessante é que algumas AIs são escritas usando os conceitos de FSM para determinar comportamentos de seus agentes, portanto, te garanto, FSMs são bastante flexíveis.
Na realidade, a ideia desta aplicação Django surgiu para atender uma demanda, onde os usuários mais graduados, deveriam poder escolher como a informação fluiria numa aplicação geográfica.
Instalação
Para instalar este pacote é bem simples e você pode usar o pip:
pip install django-workflow-fsm
Agora adicione este pacote ao seu INSTALLED_APPS
:
INSTALLED_APPS = (
# outras apps,
'workflow',
# outras apps,
)
Execute suas migrações com ./manage.py migrate
Getting Started
Terminado isto, você precisa definir qual é o modelo que você deseja controlar o status. Basta você herdar de um MixIn para obter a funcionalidade de máquina de status:
# models.py
class Projeto(StateControllerMixIn):
nome = models.CharField(max_length=128)
Pronto. A configuração básica está pronta!
Depois disso, com toda a certeza, você deve querer editar quais status e como a informação flui entre estes status. Isto é bem fácil.
Nós controlamos o fluxo de informações utilizando três modelos:
- StateMachine;
- State
- Transition;
Vamos construir isso em um passo a passo rápido:
# shell ou fixture ou migração de dados
status_aberto = State.objects.create(code='aberto')
status_em_andamento = State.objects.create(code='em-andamento')
status_fechado = State.objects.create(code='fechado')
# nossos status estão criados. Vamos criar nossa máquina de estado
fsm = StateMachine.objects.create(name='projetos-simples', initial_state=status_aberto)
# na linha acima definimos nossa máquina e o status inicial dela, aberto.
# agora vamos definir as transicoes
aberto_andamento = Transition.objects.create(name='iniciando-projeto',
machine=fsm,
from_state=status_aberto,
to_state=status_em_andamento)
andamento_fechado = Transition.objects.create(name='finalizando-projeto',
machine=fsm,
from_state=status_em_andamento,
to_state=status_fechado)
Agora que nossas transições estão prontas, você pode definir qualquer projeto, com diferentes tipos de máquinas de estado, basta escolher a máquina de estado apropriada, veja só:
projeto = Projeto()
projeto.nome = 'projeto legal'
projeto.save(state_machine=fsm)
Neste momento, todas as ações da máquina de estado estão disponíveis através do mixin que você herdou na construção do modelo Projeto.
Exemplo:
projeto.current_state
# imprime "aberto"
projeto.next
# imprime "em andamento"
projeto.change_to(state_em_andamento)
# projeto será enviado para o estado "em andamento"
projeto.next
# imprime 'fechado'
Não é só isso, existem diversos ganchos que você pode usar, como tarefas específicas a serem disparadas e ações, nas quais você pode associar a um estado, para indicar que esta ação está disponível. Exemplo: no status em andamento do projeto, vocẽ pode criar comentários e apenas neste estado. Portanto, você pode criar uma Action
e associá-la ao estado em-andamento
.
No seu código, vocẽ pode checar qual action
está disponível e renderizar o template como você achar melhor.
Outras coisas legais:
- Você pode associar permissões a cada estado, ou seja, apenas usuários com determinadas permissões podem trocar o estado da máquina;
- Você pode associar
tasks
(ou tarefas) que serão executadas quando um estado da máquina é alterado. Por exemplo, quando a máquina de estado mudar de estado, quero disparar um email para um usuário, informando do ocorrido. Você pode criar isso como umaTask
e associar esta task a transição específica. - Suporte para tarefas assíncronas. Por padrão, as tarefas são executadas usando o Celery, que é uma dependência do projeto. Caso você não queira executar estas tarefas de forma assícrona, basta desabilitar o
Celery
. - Suporte completo para API REST, usando
django-rest-framework
Repositório
Disponível no Github: https://github.com/sigma-geosistemas/django-workflow
Roadmap
- Suporte completo para tarefas assíncronas e síncronas (hoje só suportamos um modo, queriamos suportar os dois);
- Melhorar a infraestrutura de testes;
- Melhor/criar um help/ajuda/getting started;
- Outras coisitas;
Este é um pacote bem completo para gestão de máquinas de estado. Caso você tenha interesse, dê uma conferida. Estamos a disposição!