Мне нужно реализовать конечный автомат, чтобы отслеживать некоторые из моих моделей проекта 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()
Я в основном создаю «шаблонную» машину, используя интерфейс администратора, а затем запускаю метод copy, который копирует модель конечного автомата и устанавливает для шаблона значение False.
Теперь вот мои вопросы:)
Является ли использование ForeignKey в SampleModel лучшим способом присоединения StateMachine к нему?Я читал об общих отношениях в Django, но я никогда не использовал его раньше.Использовать его было бы полезно в моем сценарии?
Я пытаюсь следовать философии «Делай одно и делай хорошо», но у меня есть другие бизнес-требования для реализации.Например, мне нужно отправить, чтобы отправить электронное письмо определенной группе каждый раз, когда изменяется состояние, и эта группа меняется от штата к штату.Первым решением, которое я предложил, было добавление поля «электронная почта» в модели состояния.Но это нарушит то, что предлагает сделать это приложение - просто отслеживать конечный автомат.Каков наилучший способ решения этой проблемы?
Я также включил в модель некоторые функции ловушек, чтобы кто-то мог позже присоединить пользовательское поведение, это лучший способ сделать это?(Я думаю, что Django уже был сигнальной системой)
Есть другие идеи / комментарии?Я новичок в этой вещи многоразового использования приложений:)
Спасибо!