Modélisation d'un workflow linéaire avec Django

vignette

Pour le boulot, je devais réaliser un prototype implémentant des processus simples, c'est-à-dire représentés par une suite d'étapes ordonnées. On peut facilement se représenter un tel processus en considérant une ligne de métro avec ses stations sans ramifications.

C'est relativement simple à énoncer mais c'est un peu plus difficile à modéliser, commençons par le modèle de données appliqué à Django (simplifié) :

class Step(models.Model):
    title = models.CharField()

class Process(models.Model):
    title = models.CharField()

class ProcessWorkflow(models.Model):
    source = models.ForeignKey(Step)
    target = models.ForeignKey(Step)
    process = models.ForeignKey(Process)

On dispose donc maintenant d'étapes et de processus. La classe/table ProcessWorkflow permet de lier les étapes entre elles au sein d'un processus.

Une fois ce modèle créé, il s'agit de reconstruire le workflow lorsqu'on en a besoin. Pour cela, un fonction récursive permet assez élégamment de se sortir d'affaire. C'est peut-être ici qu'il peut y avoir mieux en termes de performance mais dans le cadre de mon prototype c'est suffisant :

def build_linear_workflow(items, steps=None, source=None):
    """ Recursive function to build a linear workflow, return a step list. """
    if steps is None:
        steps = []
    for item in items:
        if item.source == source:
            if item.target is None:
                return steps
            else:
                steps.append(item.target)
                return build_linear_workflow(items, steps, item.target)

La fonction est relativement générique car elle me permet de former des workflows d'étapes, de processus, de projets, etc. Je pense qu'elle est relativement facile à comprendre avec le nom des variables choisies (le problème de performance est au niveau de la boucle sur l'ensemble des items, je pense que je pourrais facilement retirer l'item ajouté à steps).

Il ne reste plus qu'à ajouter cette ressource sous la forme d'un propriété au précédent modèle, la classe Process devient alors :

class Process(models.Model):
    title = models.CharField()

    def get_workflow(self):
        return build_linear_workflow(ProcessWorkflow.objects.filter(process=self.id))
    workflow = property(get_workflow)

On peut maintenant utiliser directement le workflow dans un template de la façon suivante :

<h3>{{ process.title }}</h3>
{% if process.workflow %}
<ul>
    {% for step in process.workflow %}
        <li>{{ step.title }}</li>
    {% endfor %}
</ul>
{% endif %}

Simple comme Django :-).

Voici le fruit de mes recherches, merci à tous ceux qui ont contribué au résultat final, n'hésitez pas à réagir si vous avez une solution plus simple/élégante. La prochaine étape, c'est de passer aux workflows plus complexes, pouvant présenter des arborescences ascendantes et/ou descendantes. Le casse-tête ne fait que commencer...

— 23/03/2007

Articles peut-être en rapport

Commentaires

Olivier le 24/03/2007 :

Salut,

Très intéressant ton article, mais qu'entends-tu par processus? et comment utilises-tu ces processus dans ton context?

Batiste le 24/03/2007 :

Merci pour cet exemple clair. Si j'ai bien compris, à partir d'un process, on peut modéliser une arborescence d'étapes à réaliser que l'on peut récupérer sous la forme d'une liste simple.

D'où cette question : Peut gérer des structures arborescentes comme des listes imbriquées avec Django ? C'est une chose que je n'ai encore jamais vue. Le langage de template ne semble pas offrir cette fonctionnalité par défaut.

David, biologeek le 24/03/2007 :

@Olivier : des échantillons doivent suivre des suites d'étapes définies par les utilisateurs (expériences). Grâce à cette implémentation des workflows, je peux facilement représenter à l'écran ces suites d'étapes.

@Batiste : bien sûr, dans l'exemple donné, si step possède un workflow lui aussi (concept de sous-étape), il suffit de faire une boucle sur step.workflow, et ainsi de suite avec une profondeur (quasi) infinie.

Damien B le 27/03/2007 :

Vous n'avez pas de bibliothèque pour XPDL en Python ?

David, biologeek le 28/03/2007 :

Tiens je ne connaissais pas, très intéressant !

Pour l'instant la seule implémentation que j'ai trouvé en python est celle de CPS développée par Nuxeo : www.cps-project.org/secti...

Je vais creuser de ce côté là, merci.

Miloz le 17/07/2007 :

J'ai l'impression que les projets de workflow en python un peu sérieux sont pas légions, surtout depuis que Zope est passé en v3; Les produits sous Zope v2 ne sont pas migrés, et Nuxeo abandonne python pour Java.

Il y avait pourtant un projet, openflow, qui m'a l'air intéressant:
www.openflow.it/

Ce serait à mon avis intéressant de le "retranscrire" sous Django; si ça intéresse qqun, j'ai commencé à modéliser quelques models ...

David, biologeek le 17/07/2007 :

Oh, très intéressant, je veux bien voir ce que ça peut donner !

Pour l'instant j'ai commencé une implémentation from scratch car nos besoins sont très spécifiques mais je me suis grandement inspiré des workflows à activités comme openflow ou le module wfmc de Zope svn.zope.org/zope.wfmc/tr...

Quoi qu'il en soit, mon adresse est sur la page de contact ;-).

Miloz le 18/07/2007 :

J'ai mis ça sous trac: opensvn.csie.org/traccgi/...

J'ai repris le nom openflow, je dois pas avoir le droit mais bon ...

Le projet openflow contient 3 applis:

- workflow: implémentation style openflow
- leave: vide, destiné à recevoir une le clone de leave/openflow
- test: appli de test basique avec utilisation du framework test django 0.96

foufou le 09/09/2008 :

avec quel langega on peux réaliser ça, et quels sont ls outils necessaire pour créer un exemple d'un workflow.