2010-07-15 50 views
1

为了跟踪我的一些Django项目模型,我需要实现一个有限状态机器。我已经有一个类似的应用程序,但它与其他应用程序模型密切相关,不能以任何方式重用。所以我决定重新考虑它。需要一些关于为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已经是一个信号系统)

  • 其他的想法/评论?我是新来 这种可重复使用的应用程序的事情:)

谢谢!

回答

1

我在python中实现了一个有限状态机...机器模块本身的代码没有Django ...但是,这台机器用于管理Django模型上的state属性。

我认为你唯一需要的领域是state字段。其余的应该只是python声明(除非你有特殊的理由保存你的数据库中的所有内容)。

这里是这个有限状态机的东西,你可以从中获取想法,甚至可以获取整个代码并重构它。有非常好的文档,我认为它非常干净和简单:http://dl.dropbox.com/u/1869644/state_automaton.zip(你可以生成点图格式的图表!)

编辑:

我想能够在一个特定的状态链接到用户

在这种情况下(如果你想保留它通用)把用户领域在子类中你的状态自动机。例如:

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),您几乎可以做任何事情,而且非常简单:检查我发送给您的代码!

+0

我想在我的情况下,在数据库中存储所有内容是必要的。了解国家有帮助,但并不能解决我所有的问题。例如,我想能够将特定状态链接到用户,以便用户在状态更改时接收更新。 – 2010-07-15 15:06:14

+0

我认为它不会改变任何事情:检查我的编辑... – sebpiq 2010-07-15 15:38:15

+0

谢谢!我会检查代码:) – 2010-07-15 20:14:23

相关问题