Django FSM状态转换错误

时间:2015-11-04 09:40:52

标签: python django fsm

from datetime import datetime

from django.db import models
from django_fsm import FSMField, transition

class Network(models.Model):
    name = models.CharField(max_length=100, unique=True)    
    prefix = models.CharField(max_length=20, default='')
    country = models.CharField(max_length=50, default='')
    client_wsdl = models.TextField(blank=True, default='')

    class Meta:
        db_table = 'network'

    def __unicode__(self):
        return u'{0}'.format(self.name)


class SmsMessage(models.Model):
    #Define State Machine
    received, started, failed, submitted, completed = "received", "started", "failed", "submitted", "completed"
    STATE_CHOICES = (
        (received, received),
        (started, started),
        (failed, failed),
        (submitted, submitted),
        (completed, completed),
    )

    message_id = models.CharField(max_length=50)
    sender_id = models.CharField(max_length=50, default='')
    msisdn = models.CharField(max_length=50)
    message = models.CharField(max_length=200)
    priority = models.CharField(max_length=50)
    status = models.CharField(max_length=20, default='')    
    state = FSMField(default=received, choices=STATE_CHOICES, protected=True)
    callback = models.CharField(max_length=200, default='')
    network = models.ForeignKey(Network, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'sms_message'

    def __unicode__(self):
        return self.message_id

    @transition(field=state, source='received', target=started)
    def started(self):
        '''
        Change message request to started state.
        '''        
        return

    @transition(field=state, source='started', target=failed)
    def failed(self):
        '''
        For started requests that cannot be submitted to Network
        hence in a failed state.
        '''
        return

    @transition(field=state, source=started, target=submitted)   
    def submitted(self):
        '''
        Change message request to submitted state.
        '''
        return

    @transition(field=state, source='submitted', target=completed)
    def completed(self):
        '''
        Request was sucessfully submited to mno and a response returned.
        '''
        return

从上面的代码中,提交的状态转换失败并显示以下错误:

Traceback (most recent call last):
worker_1   |   File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 240, in trace_task
worker_1   |     R = retval = fun(*args, **kwargs)
worker_1   |   File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 438, in __protected_call__
worker_1   |     return self.run(*args, **kwargs)
worker_1   |   File "/app/sms_platform/apps/api/tasks.py", line 176, in run
worker_1   |     return self._send_sms(msisdn, message, request_id, correlation_id, mno, sender_id, pk=pk)
worker_1   |   File "/app/sms_platform/apps/api/tasks.py", line 126, in _send_sms
worker_1   |     sms_obj.submitted()
worker_1   |   File "/usr/local/lib/python2.7/dist-packages/django_fsm/__init__.py", line 512, in _change_state
worker_1   |     return fsm_meta.field.change_state(instance, func, *args, **kwargs)
worker_1   |   File "/usr/local/lib/python2.7/dist-packages/django_fsm/__init__.py", line 304, in change_state
worker_1   |     object=instance, method=method)
worker_1   | TransitionNotAllowed: Can't switch from state 'started' using method 'submitted'

唯一的区别是在转换源中提交的内容不会像其他内容一样引用。否则,如果我引用'提交',它就可以了。

对此感到困惑,因为所有州都是在课程开始时定义的。

2 个答案:

答案 0 :(得分:2)

您将started变量重新定义为方法名称

的问题
class SmsMessage(models.Model)
    ... started, ...= ... "started", ...

    @transition(field=state, source='received', target=started)
    def started(self):  # <- LOL
        ....

   @transition(field=state, source=started, target=submitted)   
   def submitted(self):
        ....

>>> print(SmsMessage.started)
<unbound method SmsMessage.started>

答案 1 :(得分:0)

更新

您可以在单独的类中定义您的状态。

class StateSmsMessage(object):
    RECEIVED = 'received'
    STARTED = 'started'
    ...

    CHOICES = (
        (RECEIVED, RECEIVED),
        (STARTED, STARTED),
        ...
    )

然后在转换装饰器中使用StateSmsMessage.STARTED