Django FSM state transition error
Question: 
    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.


Answer: 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>
    

