一、 前言
今天小编给大家唠叨下工单审批流的那些事。在运维平台的建设,少不了工单审批工作流的实现,虽然已经存在大量基于python甚至是django封装好的库,而且非常方面,文档也相对齐全。
但封装好的库难免会遇到扩展性差,修改起来麻烦,想增加一些自定义的功能时无从下手。今天给大家简单介绍下如何利用django实现简单的审批流,虽然谈不上最佳方式,但希望能给大家一些这方面的启发。
二、表结构设计
先上一张表结构图
我们来逐一说明:
workflow:存放所有的工单类型,如发版申请、电脑故障维修申请、wifi申请等等。
state:存放审批过程中经历的节点,如小组长、部门经理、cto等等。
transition:与state表多对多关系,存放当前一个审批节点与前一个审批节点之间的关系。其中,同意和拒绝两种条件,对应两个不同的下一审批节点。
state_obj_user:存放每张工单中,审批节点与审批用户之间的关系,在创建工单的时候生成。
workflow_state_event:流程事件,每创建一张工单时,以及同意审批使工单进入下一个状态时,都会正常一个对应的审批事件记录,包括审批人、审批时间、审批选项等等,如果审批拒绝,则不生成新的事件记录。
django_content_type:由于可能存在不止一种申请工单,为了避免每种工单建一套相似的表,可以利用 Django 内置的model映射关系表,其中包含了所有表之间的关系,可以利用该表进行外键关联。
workflow_deveplop_version:发版申请表,外键关联workflow表,保存该类申请时填写的一些信息。
三、models代码部分
from django.db import modelsfrom django.contrib.auth.models import Userfrom django.contrib.contenttypes.fields import GenericForeignKeyfrom django.contrib.contenttypes.models import ContentTypefrom django.contrib.contenttypes.fields import GenericRelationclass Workflow(models.Model): """ 工单类型表 """ name = models.CharField(max_length=100, unique=True, verbose_name=u'流程名') abbr = models.CharField(max_length=20, unique=True, default='', verbose_name=u'缩写') description = models.CharField(max_length=100, default='', verbose_name=u'工单的描述') init_state = models.ForeignKey("State", on_delete=models.SET_NULL, related_name='workflow_init_state', blank=True, null=True, verbose_name=u'初始状态') class Meta: db_table = 'workflow' verbose_name = u'工单类型表' verbose_name_plural = verbose_name def __str__(self): return self.nameclass State(models.Model): """状态表 关联到对应的流程 常见的状态: 测试审核,研发审核,运维审核,完成 """ name = models.CharField(max_length=100, verbose_name=u'状态名') workflow = models.ForeignKey("Workflow", on_delete=models.PROTECT, verbose_name=u'对应的流程名') transition = models.ManyToManyField("Transition", verbose_name=u'状态转化') class Meta: db_table = 'workflow_state' verbose_name = u'状态表' verbose_name_plural = verbose_name def get_pre_state(self): try: return self.transition.get(condition='拒绝').destination except: return None def get_latter_state(self): try: return self.transition.get(condition='同意').destination except: return None def __str__(self): return self.workflow.name + ':' + self.nameclass StateObjectUserRelation(models.Model): """obj和状态和的用户关系 """ content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') state = models.ForeignKey("State", on_delete=models.PROTECT, verbose_name=u'关联状态') users = models.ManyToManyField(User, verbose_name=u'关联用户') def __str__(self): return "%s:%s:%s" % (self.content_type.name, self.object_id, self.state.name) class Meta: unique_together = ("content_type", "object_id", "state") db_table = 'state_object_user'class Transition(models.Model): """流程转化,从一个流程转化到另一个流程 **Attributes:** name 在流程内一个唯一的转化名称 workflow 转化归属的流程,必须是一个流程实例 destination 当转化发生后的目标指向状态 condition 发生转化的条件 """ name = models.CharField(max_length=100, verbose_name=u'转化名称') workflow = models.ForeignKey("Workflow", on_delete=models.PROTECT, verbose_name=u'所属的流程') destination = models.ForeignKey("State", on_delete=models.PROTECT, related_name='transition_destination',