123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- <!doctype html>
- <html lang=fr>
- <head>
- <!-- Always define the charset before the title -->
- <meta charset=utf-8>
- <title>Modélisation d'un workflow linéaire avec Django — Biologeek — David Larlet</title>
- <!-- Define a viewport to mobile devices to use - telling the browser to assume that the page is as wide as the device (width=device-width) and setting the initial page zoom level to be 1 (initial-scale=1.0) -->
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
- <!-- Fake favicon, to avoid extra request to the server -->
- <link rel="icon" href="data:;base64,iVBORw0KGgo=">
- <link type="application/atom+xml" rel="alternate" title="Feed" href="/david/log/" />
- <link rel="manifest" href="/manifest.json">
-
- <link rel="stylesheet" href="/static/david/css/larlet-david-_J6Rv.css" data-instant-track />
-
- <noscript>
- <style type="text/css">
- /* Otherwise fonts are loaded by JS for faster initial rendering. See scripts at the bottom. */
- body {
- font-family: 'EquityTextB', serif;
- }
- h1, h2, h3, h4, h5, h6, time, nav a, nav a:link, nav a:visited {
- font-family: 'EquityCapsB', sans-serif;
- font-variant: normal;
- }
- </style>
- </noscript>
-
- <!-- Canonical URL for SEO purposes -->
- <link rel="canonical" href="https://larlet.fr/david/biologeek/archives/20070323-modelisation-d-un-workflow-lineaire-avec-django">
-
- </head>
- <body>
- <div>
-
- <header>
- <nav>
- <p>
- <small>
- Je suis <a href="/david/" title="Profil public">David Larlet</a>, <a href="/david/pro/" title="Activité professionnelle">artisan</a> du web qui vous <a href="/david/pro/accompagnement/" title="Activité d’accompagnement">accompagne</a><span class="more-infos"> dans l’acquisition de savoirs pour concevoir des <a href="/david/pro/produits-essentiels/" title="Qu’est-ce qu’un produit essentiel ?">produits essentiels</a></span>. <span class="more-more-infos">Discutons ensemble d’une <a href="/david/pro/devis/" title="En savoir plus">non-demande de devis</a>.</span> Je partage ici mes <a href="/david/blog/" title="Expériences bienveillantes">réflexions</a> et <a href="/david/correspondances/2017/" title="Lettres hebdomadaires">correspondances</a>.
- </small>
- </p>
- </nav>
- </header>
-
-
- <section>
- <h1 property="schema:name">Modélisation d'un workflow linéaire avec Django</h1>
- <article typeof="schema:BlogPosting">
- <div property="schema:articleBody">
- <img src="/static/david/biologeek/images/logos/django.png" alt="vignette" style="float:left; margin: 0.5em 1em;" property="schema:thumbnailUrl" />
- <p>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.</p>
-
- <p>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é) :</p>
-
- <pre>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)</pre>
-
- <p>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.</p>
-
- <p>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 :</p>
-
- <pre>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)</pre>
-
- <p>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).</p>
-
- <p>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 :</p>
-
- <pre>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)</pre>
-
- <p>On peut maintenant utiliser directement le workflow dans un template de la façon suivante :</p>
-
- <pre><h3>{{ process.title }}</h3>
- {% if process.workflow %}
- <ul>
- {% for step in process.workflow %}
- <li>{{ step.title }}</li>
- {% endfor %}
- </ul>
- {% endif %}</pre>
-
- <p>Simple comme Django :-).</p>
-
- <p>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...</p>
- </div>
- </article>
- <footer>
- <h6 property="schema:datePublished">— 23/03/2007</h6>
- </footer>
- </section>
- <section>
- <div>
- <h3>Articles peut-être en rapport</h3>
- <ul>
- <li><a href="/david/biologeek/archives/20080902-sortie-de-django-10-une-annee-de-nouveautes/" title="Accès à Sortie de Django 1.0, une année de nouveautés">Sortie de Django 1.0, une année de nouveautés</a></li>
- <li><a href="/david/biologeek/archives/20071007-des-vacances-et-des-liens/" title="Accès à Des vacances et des liens">Des vacances et des liens</a></li>
- <li><a href="/david/biologeek/archives/20070807-une-solution-pour-faciliter-la-conception-d-applications-web-restful-avec-django/" title="Accès à Une solution pour faciliter la conception d'applications web RESTful avec Django">Une solution pour faciliter la conception d'applications web RESTful avec Django</a></li>
- </ul>
- </div>
- </section>
- <section>
- <div id="comments">
- <h3>Commentaires</h3>
-
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">Olivier</span> le <span class="comment-date" property="schema:commentTime">24/03/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>Salut,<br />
- <br />
- Très intéressant ton article, mais qu'entends-tu par processus? et comment utilises-tu ces processus dans ton context?</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">Batiste</span> le <span class="comment-date" property="schema:commentTime">24/03/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>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.<br />
- <br />
- 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.</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">David, biologeek</span> le <span class="comment-date" property="schema:commentTime">24/03/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>@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.<br />
- <br />
- @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.</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">Damien B</span> le <span class="comment-date" property="schema:commentTime">27/03/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>Vous n'avez pas de bibliothèque pour XPDL en Python ?</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">David, biologeek</span> le <span class="comment-date" property="schema:commentTime">28/03/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>Tiens je ne connaissais pas, très intéressant !<br />
- <br />
- Pour l'instant la seule implémentation que j'ai trouvé en python est celle de CPS développée par Nuxeo : <a href="http://www.cps-project.org/sections/documentation/developers/cpsworkflow/switchLanguage/fr" title="http://www.cps-project.org/sections/documentation/developers/cpsworkflow/switchLanguage/fr" rel="nofollow">www.cps-project.org/secti...</a><br />
- <br />
- Je vais creuser de ce côté là, merci.</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">Miloz</span> le <span class="comment-date" property="schema:commentTime">17/07/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>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.<br />
- <br />
- Il y avait pourtant un projet, openflow, qui m'a l'air intéressant:<br />
- <a href="http://www.openflow.it/" title="http://www.openflow.it/" rel="nofollow">www.openflow.it/</a><br />
- <br />
- Ce serait à mon avis intéressant de le "retranscrire" sous Django; si ça intéresse qqun, j'ai commencé à modéliser quelques models ...</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">David, biologeek</span> le <span class="comment-date" property="schema:commentTime">17/07/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>Oh, très intéressant, je veux bien voir ce que ça peut donner !<br />
- <br />
- 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 <a href="http://svn.zope.org/zope.wfmc/trunk/src/zope/wfmc/README.txt?rev=75443&view=markup" title="http://svn.zope.org/zope.wfmc/trunk/src/zope/wfmc/README.txt?rev=75443&view=markup" rel="nofollow">svn.zope.org/zope.wfmc/tr...</a><br />
- <br />
- Quoi qu'il en soit, mon adresse est sur la page de contact ;-).</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">Miloz</span> le <span class="comment-date" property="schema:commentTime">18/07/2007</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>J'ai mis ça sous trac: <a href="https://opensvn.csie.org/traccgi/openflow" title="https://opensvn.csie.org/traccgi/openflow" rel="nofollow">opensvn.csie.org/traccgi/...</a><br />
- <br />
- J'ai repris le nom openflow, je dois pas avoir le droit mais bon ...<br />
- <br />
- Le projet openflow contient 3 applis:<br />
- <br />
- - workflow: implémentation style openflow<br />
- - leave: vide, destiné à recevoir une le clone de leave/openflow<br />
- - test: appli de test basique avec utilisation du framework test django 0.96</p>
- </div>
- </div>
- <div class="comment" typeof="schema:UserComments">
- <p class="comment-meta">
- <span class="comment-author" property="schema:creator">foufou</span> le <span class="comment-date" property="schema:commentTime">09/09/2008</span> :
- </p>
- <div class="comment-content" property="schema:commentText">
- <p>avec quel langega on peux réaliser ça, et quels sont ls outils necessaire pour créer un exemple d'un workflow.</p>
- </div>
- </div>
-
- </div>
- </section>
-
-
- <footer>
- <nav>
- <p>
- <small>
- Je réponds quasiment toujours aux <a href="mailto:david%40larlet.fr" title="Envoyer un email">emails</a> (<a href="/david/signature/" title="Ma signature actuelle avec possibilité de chiffrement">signés</a>) et vous pouvez me rencontrer à Montréal. <span class="more-infos">N’hésitez pas à <a href="/david/log/" title="Être tenu informé des mises à jour">vous abonner</a> pour être tenu informé des publications récentes.</span>
- </small>
- </p>
- </nav>
- </footer>
-
- </div>
-
- <script src="/static/david/js/larlet-david-3ee43f.js" data-no-instant></script>
-
- <script data-no-instant>InstantClick.init()</script>
-
- </body>
- </html>
|