Ich arbeite daran, eine Workflow-Engine in meinem Projekt zu implementieren und der Hauptzweck meines Versuchs ist es, eine portable App zu erstellen. Etwas, das ich in Zukunft in jedes andere Projekt einfügen könnte, und dann Workflows an verschiedene Modelle in meinen Projekten anhängen und sie zum Laufen bringen.Django Workflow-Engine mit Signalen und Sellerie-Django
Ich habe versucht, an einen Ansatz zu denken, aber es scheint nicht das perfekte Setup zu sein. Ich dachte daran, eine Workflow-App in meinem Projekt zu erstellen, zwei Arten von Modellen anzuhängen, einige enthalten die Einrichtung eines Workflow (Workflow, Schritte, Aktionen) und andere Modelle enthalten die Instanzen/Transaktionen.
Unten ist mein Workflow/models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
import signals
################################
# Workflow engine models
################################
class Signal_Listener(models.Model):
LISTENING_ON = (
('I', 'INSERT'),
('U', 'UPDATE'),
('D', 'DELETE'),
('S', 'SELECT'),
('A', 'ANY QUERY'),
('L', 'ANY DDL'),
)
table_name = models.CharField(max_length=100)
listening_to = models.CharField(max_length=1, choices=LISTENING_ON)
class Meta:
unique_together = (("table_name", "listening_to"),)
def __unicode__(self):
return '%s - %s' % (self.table_name, self.listening_to)
class Action(models.Model):
ACTION_TYPE_CHOICES = (
('P', 'Python Script' ),
('C', 'Class name' ),
)
name = models.CharField(max_length=100)
action_type = models.CharField(max_length=1, choices=ACTION_TYPE_CHOICES)
audit_obj = generic.GenericRelation('core.Audit', editable=False)
class Steps(models.Model):
sequence = models.IntegerField()
Action = models.ForeignKey(Action)
Signal_Listener = models.ForeignKey(Signal_Listener)
class Process(models.Model):
## TODO: Document
# Processes class is used to store information about the process itself.
# Or in another word, the workflow name.
WF_TYPE_LIST = (
('P', 'Python-API'),
)
name = models.CharField(max_length=30)
is_active = models.BooleanField()
wf_type = models.CharField(max_length=1, choices=WF_TYPE_LIST)
audit_obj = generic.GenericRelation('core.Audit', editable=False)
listening_to = models.ForeignKey(Steps)
################################
# Workflow transactions models
################################
class Instance(models.Model):
## TODO: Document
# Re
INSTANCE_STATUS = (
('I', 'In Progress'),
('C', 'Cancelled' ),
('A', 'Archived' ), # Old completed tasks can be archived
('P', 'Pending' ),
('O', 'Completed' )
)
id = models.CharField(max_length=200, primary_key=True)
status = models.CharField(max_length=1, choices=INSTANCE_STATUS, db_index=True)
audit_obj = generic.GenericRelation('core.Audit', editable=False)
def save(self, *args, **kwargs):
# on new records generate a new uuid
if self.id is None or self.id.__len__() is 0:
import uuid
self.id = uuid.uuid4().__str__()
super(Instances, self).save(*args, **kwargs)
class Task(models.Model):
TASK_STATUS = (
('S', 'Assigned' ),
('I', 'In Progress'),
('P', 'Pending' ),
('C', 'Cancelled' ),
('A', 'Archived' ), # Old completed tasks can be archived
('O', 'Completed' )
)
name = models.CharField(max_length=100)
instance = models.ForeignKey(Instance)
status = models.CharField(max_length=1, choices=TASK_STATUS)
bio = models.CharField(max_length=100)
audit_obj = generic.GenericRelation('core.Audit', editable=False)
und ich habe auch ein Workflow/signals.py
"""
Workflow Signals
Will be used to monitor all inserts, update, delete or select statements
If an action is attached to that particular table, it will be inserted Celery-Tasks distribution.
"""
from django.db.models.signals import post_save, post_delete
from django.core.cache import cache
def workflow_post_init_listener(sender, **kwargs):
try:
if cache.get('wf_listner_cache_%s' % kwargs['instance']._meta.db_table):
pass
else:
record = 'Signal_Listener'.objects.get(table_name__exact=kwargs['instance']._meta.db_table)
# am not sure what to do next!
except 'Signal_Listener'.DoesNotExist:
# TODO: Error logging
pass
post_save.connect(workflow_post_init_listener, dispatch_uid="workflow.models.listener.save")
Ich glaube, mein Design-Modell könnte auch verbessert werden müssen. Ich könnte in verschiedenen Szenarien verwenden und ich dachte, mit dem Genehmigungszyklus zu beginnen, zum Beispiel könnte ich den table_name/model_name in signal_listener einfügen, um auf neue Einsätze zu überwachen. Wenn ja, werde ich einen bestimmten Workflow auslösen.
Wie für Aktionen, ich verstehe, dass Aktionen entwickelt werden müssen. Vielleicht muss ich unter der Workflow-App einen Aktionsordner erstellen und jede Aktion in eine Klasse einfügen. Jeder wird eine bestimmte Aufgabe des Sendens von E-Mails, Archivierung, Update-Datenbank-Wert .. etc
Wenn das Rad neu erfinden und wenn es so etwas gibt, das bereits entwickelt wurde, kann jemand vorschlagen, ich wäre mehr als glücklich durchgehen.
Mit freundlichen Grüßen,
Ich denke, Ihre Frage könnte umformuliert werden. Es ist nicht klar, was du wirklich fragst. – roman