我在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:据我了解,我只能为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 +)。
[edit]发生在我身上,暂时明确禁用state
方法中set_state
字段的保护可能是解决此问题的另一种方法,如果我能弄清楚如何...
答案 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);