本文将介绍工单通知实现过程中的一些小技巧。所有演示均基于Django2.0
阅读此篇文章你可以:
- 解锁一个python if的使用新姿势
- 获取一个利用signals做通知的真实案例
背景说明
先看看工单表简化后的结构
class Ticket(models.Model):
\'\'\'工单表\'\'\'
STATE = (
(1, \'待审批\'),
(2, \'已撤销\'),
(3, \'已通过\'),
(4, \'被拒绝\'),
(5, \'已挂起\'),
(6, \'执行中\'),
(7, \'已完成\'),
(8, \'已失败\')
)
create_time = models.DateTimeField(auto_now_add=True, verbose_name=\'创建时间\')
create_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name=\'创建用户\')
state = models.IntegerField(choices=STATE, default=1, verbose_name=\'工单状态\')
Ticket工单表有一个state字段标识当前工单状态,这个状态会随着工单的进行而改变,每当工单状态改变时就需要发送通知给相应的用户,例如工单创建时,需要发送给创建者一个工单创建成功的通知,同时发送给审核者一个待审核的通知
通知
每一个状态的变化都需要通知,为了代码易读及解耦,我们需要写一个单独的通知类,当需要通知的时候调用一下就好了。通知类中需要判断当前工单的状态,那么通常会写成下边这样
class Notify:
def __init__(self):
self.dba_list = [\"dba1@ops-coffee.cn\", \"dba2@ops-coffee.cn\"]
def migration(self, pk):
\'\'\'迁移通知\'\'\'
_t = Ticket. s.get(id=pk)
_u = _t.create_user.username
_s = _t.state
_d = \"https://ops-coffee.cn/workflow/migration/%d/\" % (_t.id)
if _s == 1:
try:
Email(
subject=\"[已提交]-[overmind]数据迁移工单\",
content=\"你的数据迁移工单已提交,正在等待DBA审批,后续有状态变更将会自动通知你。\\r\\n\\r\\n工单详情:%s\" % _d,
reciever_list=[_u]
)
except Exception as e:
print(\'Error:\' + str(e))
try:
Email(
subject=\"[待审批]-[overmind]数据迁移工单\",
content=\"你有工单需要审批,点击下方工单详情链接及时审批。\\r\\n\\r\\n工单详情:%s\" % _d,
reciever_list=self.dba_list
)
except Exception as e:
print(\'Error:\' + str(e))
elif _s == 6:
try:
Email(
subject=\"[执行中]-[overmind]数据迁移工单\",
content=\"数据迁移工单已通过DBA审核,正在执行中,后续有状态变更将会自动通知你。\\r\\n\\r\\n工单详情:%s\" % _d,
reciever_list=[_u] + self.dba_list,
)
except Exception as e:
print(\'Error:\' + str(e))
elif _s == 7:
try:
Email(
subject=\"[已完成]-[overmind]数据迁移工单\",
content=\"数据迁移工单已自动完成迁移,请检查最终状态,如有任何疑问随时联系DBA。\\r\\n\\r\\n工单详情:%s\" % _d,
reciever_list=[_u] + self.dba_list,
)
except Exception as e:
print(\'Error:\' + str(e))
以上的代码可以看出来写了很多重复的try代码,并且当状态越多,if判断越复杂时重复的代码也会越来越多,有没有更简洁的方式呢?
看看下边的代码,维护一个状态字典,然后用一个if判断就可以实现上边一堆if的代码写法,是不是就简洁了很多
class Notify:
def __init__(self):
self.dba_list = [\"dba1@ops-coffee.cn\", \"dba2@ops-coffee.cn\"]
def migration(self, pk):
\'\'\'迁移通知\'\'\'
_t = Ticket. s.get(id=pk)
_u = _t.create_user.username
_s = _t.state
_d = \"https://ops-coffee.cn/workflow/migration/%d/\" %(_t.id)
smap = {
1: [{
\"subject\": \"[已提交]-[overmind]数据迁移工单\",
\"content\": \"你的数据迁移工单已提交,正在等待DBA审批,后续有状态变更将会自动通知你。\\r\\n\\r\\n工单详情:%s\" %_d,
\"reciever_list\": [_u],
}, {
\"subject\": \"[待审批]-[overmind]数据迁移工单\",
\"content\": \"你有工单需要审批,点击下方工单详情链接及时审批。\\r\\n\\r\\n工单详情:%s\" %_d,
\"reciever_list\": self.dba_list,
}],
6: [{
\"subject\": \"[执行中]-[overmind]数据迁移工单\",
\"content\": \"数据迁移工单已通过DBA审核,正在执行中,后续有状态变更将会自动通知你。\\r\\n\\r\\n工单详情:%s\" %_d,
\"reciever_list\": [_u] + self.dba_list,
}],
7: [{
\"subject\": \"[已完成]-[overmind]数据迁移工单\",
\"content\": \"数据迁移工单已自动完成迁移,请检查最终状态,如有任何疑问随时联系DBA。\\r\\n\\r\\n工单详情:%s\" %_d,
\"reciever_list\": [_u] + self.dba_list,
}]
}
_list = smap[_s]
for i in range(0, len(_list)):
try:
Email(
subject=_list[i][\'subject\'],
content=_list[i][\'content\'],
reciever_list=_list[i][\'reciever_list\']
)
except Exception as e:
print(\'Error:\' +str(e))
在构造字典的时候采用了状态做key,通知变量做value,同时一个状态可能会产生多个不同的通知,所以value采用列表的方式,这样即可轻松实现一个状态多条通知,每条通知都可以发给不同的人,有不同的主题,不同的内容。
Signals
上边我们已经写好了发送通知的类,在view里每次修改工单状态之后调用下通知类即可实现通知发送,但这样通知跟view强耦合,且通知会分散在view中的多个地方,造成代码冗余且不够优雅。我们需要一个简单优雅的方式来实现,signals可以说是非常有用了
Signals是Django自带的一个信号调度程序。如果你对svn或者git之类的hooks有了解,这个理解起来就简单多了,通俗来说就是当你的程序产生一个事件时,会通过signals自动触发其他的事件。就比如我们这个工单系统通知,当工单状态产生变化时自动发送邮件给相关人。
Django内部已经定义好了一些signal供我们使用,如果不能满足我们也可以自定义signal,其中Django内部定义的signal主要分为几类
model signals pre_init post_init pre_save post_save pre_delete post_delete m2m_changed class_prepared management signals pre_migrate post_migrate request/response signals request_started request_finished got_request_exception test signals setting_changed template_rendered Data Wrappers connection_created :连接建立时触发
那么信号究竟该如何使用呢?下边一个实际的例子来说明下信号的使用
就以我们发送通知的需求为例,workflow是一个普通的app,第一步需要新建 workflow/signals.py 文件绑定signal
from django.db.models import signals
from django.dispatch import receiver
from workflow.models import Ticket
from workflow.backends.notify import Notify
@receiver(signals.post_init, sender=Ticket)
def migrate_notify_init(instance, **kwargs):
instance.old_state = instance.state
@receiver(signals.post_save, sender=Ticket)
def migrate_notify_post(instance, created, **kwargs):
if created or instance.old_state != instance.state:
Notify().migration(instance.id)
这里用到了两个signal, post_init 和 post_save
在model初始化之后通过 post_init 信号获取到state的值作为初始状态值,在每次model执行save方法后调用 post_save 信号获取到新的状态值,对两次状态值做比较如果不一致则表示状态有更新发送通知
是上边的判断只能判断到状态变更了发通知,但工单在第一次创建时old_state和state是一样的,所以也需要在save之后判断下这次操作是不是新建,如果是新建同样需要发送通知
第二步加载signal,需要修改两个配置文件
config1: workflow/apps.py
from django.apps import AppConfig
class WorkflowConfig(AppConfig):
name = \'workflow\'
def ready(self):
import workflow.signals
config2: workflow/__init__.py
default_app_config = \'workflow.apps.WorkflowConfig\'
绑定成功后就可以在每次工单状态发生变化时发送邮件了
总结
以上所述是小编给大家介绍的Django使用Signals监测model字段变化发送通知的一些技巧,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
继续阅读与本文标签相同的文章
如何开发一款游戏:游戏开发流程及所需工具
-
在AlibabaCloud上,如何使用AD FS进行 【角色SSO】 并完成在容器服务ACK集群中的身份验证
2026-05-19栏目: 教程
-
骚操作 !用 Python 偷偷抓取女朋友的行踪(女朋友在哪里)
2026-05-19栏目: 教程
-
受用一生的高效 PyCharm 使用技巧(五)
2026-05-19栏目: 教程
-
阿里云服务器从购买到入门使用流程 新手必看教程
2026-05-19栏目: 教程
-
2019云栖大会,智能视频云专场硬核分享来了!
2026-05-19栏目: 教程
