Django Workflow

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 uma Task 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!