title: Need some advice regarding writing an reusable app for Django
body: <p>I need to implement a finite-state-machine in order to keep track of a few of my Django project models. I already have a similar app doing that but it's heavily coupled with the others apps models and not reusable in any way. So I decided to re-factor it.</p>
  
  <p>After a few hours, this is what I came up with:</p>
  
  <pre><code>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):
          ...
  </code></pre>
  
  <p>I am happy with the results. It does what a state machine is expected to do and nothing else. In my models I am using it like this:</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>I basically create a "template" machine using the admin interface and then I run copy method which copies the state machine model and sets the template to False.</p>
  
  <p>Now, here comes my questions :)</p>
  
  <ul>
  <li><p>Is using a ForeignKey in the SampleModel the best way to attach
  the StateMachine to it? I've read
  about Generic Relations in Django but
  I've never used it before. Using it would be beneficial in my scenario?</p></li>
  <li><p>I am trying to follow the "Do one
  thing and do it well" philosophy,
  but I've other business
  requirements to implement. For
  example, I need to send to send an e-mail to a specific group every time a state changes, and this group varies from state to state. The first solution I came up was to add an "email" field in the state model. But this would violate what this app proposes to do which is simply to keep track of a state machine. What would be the best way to solve this problem?</p></li>
  <li><p>I also include some hook functions in
  the model so that someone could
  attach custom behavior later, is this
  the best way to do it? (I think
  Django was already a signal system)</p></li>
  <li><p>Any other ideas/comments? I am new to
  this reusable apps thing :)</p></li>
  </ul>
  
  <p>Thanks!</p>