我需要实现一个有限状态机来跟踪我的一些Django项目模型。我已经有一个类似的应用程序,但它与其他应用程序模型严重耦合,不能以任何方式重复使用。所以我决定重新考虑它。
几个小时后,这就是我提出的:
class StateMachine(models.Model):
name = models.CharField(max_length=50, help_text="Must be an unique name")
template = models.BooleanField(default=True)
current_state = models.ForeignKey('State', blank=True, null=True, related_name='current_state')
initial_state = models.ForeignKey('State', blank=True, null=True, related_name='initial_state')
def get_valid_actions(self):
return Action.objects.filter(machine=self, from_state=self.current_state)
def copy(self):
...
class State(models.Model):
name = models.CharField(max_length=50)
machine = models.ForeignKey(StateMachine)
def enter_hook(self, machine=None, action=None, state=None):
pass
def exit_hook(self, machine=None, action=None, state=None):
pass
def _copy(self, machine):
...
class Action(models.Model):
name = models.CharField(max_length=50)
machine = models.ForeignKey(StateMachine)
from_state = models.ForeignKey(State, related_name='from_state')
to_state = models.ForeignKey(State, blank=True, null=True, related_name='to_state')
def is_valid(self):
if self.machine.current_state == self.from_state:
return True
else:
return False
def act(self):
if self.is_valid():
self.from_state.exit_hook(machine=self.machine, action=self, state=self.from_state)
self.machine.current_state = self.to_state
self.machine.save()
self.to_state.enter_hook(machine=self.machine, action=self, state=self.to_state)
else:
raise ActionNotApplicable()
return self.machine
def _copy(self, machine):
...
我对结果很满意。它完成了状态机预期要做的事情而不是其他事情。在我的模型中,我使用它是这样的:
class SampleModel(models.Model):
machine = models.ForeignKey(StateMachine, null=True)
def setup_machine(self):
self.machine = StateMachine.objects.get(template=True, name='bla bla bla').copy()
self.save()
我基本上使用管理界面创建一个“模板”机器,然后运行复制方法,复制状态机模型并将模板设置为False。
现在,我的问题出现了:)
在SampleModel中使用ForeignKey是最佳附加方式 StateMachine到了吗?我读了 关于Django中的通用关系但是 我以前从未使用过它。在我的场景中使用它会有益吗?
我想跟随“做一个 事情并且做得很好“哲学, 但我还有其他事情 要求实施。对于 例如,我需要发送每次状态更改时向特定组发送电子邮件,并且该组因州而异。我提出的第一个解决方案是在状态模型中添加“email”字段。但这违反了这个应用程序建议做的事情,这只是为了跟踪状态机。什么是解决这个问题的最佳方法?
我还包括一些钩子函数 该模型,以便有人可以 稍后附加自定义行为,是这样的 最好的方法吗? (我认为 Django已经是一个信号系统了)
还有其他想法/评论吗?我是新来的 这个可重复使用的应用程序:)
谢谢!
答案 0 :(得分:1)
我在python中实现了一个有限状态机...机器模块本身的代码没有Django ......但是,这台机器用于管理Django模型上的state
属性。 / p>
我认为您真正需要的唯一字段是state
字段。其余的应该只是python声明(除非你有特殊的理由保存数据库中的所有内容)。
这是有限状态机的东西,你可以从中获取想法,甚至可以获取整个代码并重构它。有非常好的文档,我认为它非常简洁:http://dl.dropbox.com/u/1869644/state_automaton.zip(你可以生成点格式的图表!)
编辑:
我希望能够将特定状态链接到用户
在这种情况下(如果要保持通用),将users字段放在state automaton的子类中。例如:
class UserAlertStateAutomaton(FiniteStateAutomaton):
"""
An automaton that alerts users when the state changes
"""
users_to_alert = models.ManyToManyField(User)
def change_state(self, new_state):
"""
overrides the parent method to alert users that state has changed
"""
super(UserAlertStateAutomaton, self).change_state(new_state)
for user in self.users_to_alert:
#do your thing
def subscribe#... etc
这仍然意味着除了基本状态自动机类中的状态之外,您不需要保存任何其他内容。通过实现一个钩子系统(当从状态A转换到状态B时执行一个方法X),你几乎可以做任何事情,而且非常简单:检查我发给你的代码!