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
From my code above, submitted state transitions fail with this error:
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'
The only difference is that submitted in transition source is NOT quoted like the others. Otherwise if I quote 'submitted', it works okay.
Am puzzled at this since all the states are defined at the beginning of the class.
The problem that you have started
variable redifined to the method name
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>