2010-07-15 2 views
1

장고 프로젝트 모델 중 몇 가지를 추적하기 위해 유한 상태 기계를 구현해야합니다. 이미 비슷한 응용 프로그램을 사용하고 있지만 다른 응용 프로그램 모델과 많이 결합되어 어떤 식 으로든 재사용 할 수는 없습니다. 그래서 저는 그것을 다시 고려하기로 결정했습니다.장고를위한 재사용 가능한 응용 프로그램 작성에 대한 조언이 필요합니다.

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의 외래 키 그것에 머신 (StateMachine)를 연결하는 가장 좋은 방법을 사용하여 내 질문 : 온다? 내가 장고에서 일반 관계에 대해 을 읽었으나, 나는 전에 그것을 사용한 적이 없다. 그것은 내 시나리오에서 도움이 될까요?
  • 나는, 을 "한 일을 할 잘 그것을"철학을 따라하려고하지만 구현 다른 비즈니스 요구 사항을했습니다. 예를 들어 상태가 변경 될 때마다 특정 그룹에 전자 메일을 보내려면이 그룹을 상태별로 바꿔야합니다. 첫 번째 해결책은 상태 모델에 "전자 메일"필드를 추가하는 것입니다. 그러나 이것은이 응용 프로그램이 단순히 국가 시스템을 추적하는 것임을 제안하는 것에 위배됩니다. 이 문제를 해결하는 가장 좋은 방법은 무엇입니까? 그래서

  • 나는 또한 모델의 일부 후크 기능을 포함
  • 사람은 나중에 사용자 정의 동작을 첨부 할 수 있습니다,이 그것을 할 수있는 가장 좋은 방법입니다? (나는 장고가 이미 신호 시스템이라고 생각했다.)

  • 다른 생각이나 의견이 있으십니까? 나는 에 재사용 할 수있다. 재사용 할 수있는 앱이다.

고마워!

답변

1

필자는 파이썬으로 유한 상태 기계를 구현했습니다 ... 기계 모듈 자체의 코드에는 장고가 없습니다 ... 그러나이 기계는 장고 모델에서 state 속성을 관리하는 데 사용되었습니다.

내가 갖고 있어야하는 유일한 필드는 state 필드입니다. 나머지는 파이썬 선언 일뿐입니다 (데이터베이스에 모든 것을 저장하는 특별한 이유가없는 한).

여기에이 유한 상태 기계가 있습니다. 아이디어를 가져올 수도 있고, 전체 코드를 리팩토링 할 수도 있습니다. 아주 좋은 문서가 있습니다. 나는 꽤 깨끗하고 단순하다고 생각합니다 : http://dl.dropbox.com/u/1869644/state_automaton.zip (도트 형식으로 도형을 생성 할 수 있습니다 !!!)

편집

: 당신이 제네릭을 유지하려면

I 싶어 (이 경우에서, 사용자

에 특정 상태를 연결할 수)이 서브 클래스의 사용자 필드를 넣어 당신의 국가 자동 장치의. 예를 들어 : 아직도 당신이 기본 상태 자동 장치 클래스의 상태 보다 무엇을 저장할 필요가 없습니다 것을 의미

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

제 경우에는 데이터베이스에 모든 것을 저장해야합니다. 국가를 아는 것은 도움이되지만 내 모든 문제를 해결하지는 못합니다. 예를 들어 특정 상태를 사용자에게 연결하여 상태가 변경 될 때 사용자가 업데이트를 수신 할 수있게하고 싶습니다. –

+0

나는 그것이 아무것도 바뀌지 않는다고 생각한다 : 나의 편집을 확인하라. – sebpiq

+0

고마워! 내가 코드를 확인합니다 :) –

관련 문제