你能编写一个针对任意状态的django-fsm转换吗?

时间:2016-02-10 10:10:46

标签: python django django-models state-machine

我在state字段(类型为FSMField)上使用django-fsm来跟踪整个过程中的样本管。我需要允许一些高级用户将对象从一个状态“跳转”到另一个状态,在发生时记录并发送通知。我的问题是:如何在避免代码重复(即DRY)的同时编写此转换?

更多详情:

我在我的FSMField上设置了protected=True:我非常喜欢它提供的保护 - 没有其他代码路径可以更改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:据我了解,我只能为targetdocs 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 +)。

[edit]发生在我​​身上,暂时明确禁用state方法中set_state字段的保护可能是解决此问题的另一种方法,如果我能弄清楚如何...

1 个答案:

答案 0 :(得分:1)

虽然作为django-fsm的作者,我非常不建议使用你的方法,但我认为最终它可能会导致if-elif垃圾内set_state功能,我建议,不要将其作为模型方法实现。

而是只创建一个常规函数,并直接更新db状态。

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