2016-02-10 4 views
2

Я использую django-fsm на поле state (тип FSMField) для отслеживания пробных проб через процесс. Мне нужно, чтобы некоторые опытные пользователи могли «перескакивать» объекты из одного состояния в другое, регистрировать и отправлять уведомления, когда это происходит. Мой вопрос: Как написать этот переход, избегая повторения кода (т. Е. СУХОЙ)?Можете ли вы закодировать переход django-fsm, который нацелен на произвольное состояние?

Подробнее:

Я установил protected=True на моем FSMField: мне очень нравится защиты он предоставляет - никаких других путей кода не в состоянии изменить state.

Вот основы (примечание: не полный код, не будут работать, только для иллюстрации)

class SampleTube(model.Model): 
    state = FSMField(default='new', choices=(...), protected=True) 

    @transition(field=state, source='*', target='*', permission='my_app.superpowers') # <-- problem 1 
    def set_state(self, user, new_state): 
     assert is_valid_state(new_state) 
     log_event(self, user, new_state) 
     send_notification(self, self.owner) 
     self.state = new_state # <-- problem 2 

Проблема 1: Как я понимаю, я могу использовать только одно значение строки для target (docs link). Справедливо. Мне нравится то, что модели метода вызова автоматически устанавливают state. Поэтому я не думаю, что могу написать переход к произвольному состоянию.

Проблема 2: Если я хочу, чтобы сохранить protected=True (по указанным выше причинам), я не могу напрямую изменять state поля (поднимает AttributeError, как описано)

ли я прибегнуть к написанию этого в моем модель класса? Есть ли какой-то метод метапрограммирования, который будет держать меня сухим?

@transition(field=state, source='*', target='used', permission='myapp.superpowers') 
def set_used(self, user): 
    # ... 

@transition(field=state, source='*', target='received', permission='myapp.superpowers') 
def set_received(self, user): 
    # ... 

#... loads more set_xyz methods that all have the same signature... 

Поэтому я хочу, чтобы решить эту проблему (кроме с удовлетворением краткого кода) является то, что число возможных состояний достаточно велико (10+).

[править] Происходит мне, что временно, явно отключить защиту на state поле внутри метода set_state может быть еще один способ приблизиться к этому, если бы я мог работать, как ...

+0

Вообще говоря, я не вижу правильный ответ на ваш вопрос, б/с вопрос неверен. Pythonic подход настаивает на том, что явный лучше, чем неявный. Это то, что делает django-fsm. Как только ваше требование изменится, и вам нужно пропустить или выполнить отдельное действие при изменении состояния суперпользователя, любой общий подход приведет вас к огромному рефакторингу. – kmmbvnr

+0

Я надеялся найти способ, который является pythonic и не повторяющимся. Я думаю, что я являюсь явным, потому что в сигнатуре метода, предложенной явным образом, есть параметр 'new_state' в качестве параметра и явно имеет разрешение, требуемое в декораторе. Возможно, я скучаю по тебе. – mozz100

+0

Я думаю, вы неправильно поняли СУХОЙ. DRY означает, что один вопрос дает ответ только в одном месте. В этом случае вы пытаетесь решить N вопросов в одном месте (когда и как администратор может изменить состояние XXX в YYY). Правильное решение DRY должно состоять в том, чтобы иметь N переходных методов состояния, который вызывает один метод log/send_notify. – kmmbvnr

ответ

1

Хотя как автор Джанго -fsm Мне очень не рекомендуется использовать ваш подход, я думаю, что в конце концов это может привести к ошибке в if-elif мусор внутри функции set_state, я мог бы предложить, а не реализовывать его как метод модели.

Вместо этого просто выполните обычную функцию и обновите состояние db напрямую.

def set_state(tube, new_state): SampleTube.objects.filter(pk=tube.pk).update(state=new_state);

+0

Спасибо - это хороший совет, я ценю ваш опыт и постараюсь сделать так. Одна из задач, сделанных таким образом, заключается в том, что экземпляры в памяти не получают обновление до своего свойства 'state', и я не могу вызывать' refresh_from_db() 'на модели с защищенными полями. Есть ли решение для моего оригинала subquestion (см. редактирование внизу): могу ли я явно временно отключить защиту в поле? – mozz100

+0

Нет, нет никакого хакерского способа отключить защиту поля в django_fsm. Эта функция отсутствует. B/c с 'set_state()' не является явным и не следует fsm paradigm. – kmmbvnr