Нужен совет относительно написания многоразового приложения для Django - PullRequest
1 голос
/ 15 июля 2010

Мне нужно реализовать конечный автомат, чтобы отслеживать некоторые из моих моделей проекта 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 уже был сигнальной системой)

  • Есть другие идеи / комментарии?Я новичок в этой вещи многоразового использования приложений:)

Спасибо!

1 Ответ

1 голос
/ 15 июля 2010

Я сам реализовал конечный автомат в python ... Код самого модуля машины не имеет Django ... Однако эта машина использовалась для управления атрибутом state в модели Django.

Я думаю, что единственное поле, которое вам действительно нужно, это поле 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), вы можете сделать что угодно и очень просто: проверьте код, который я вам отправил!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...