Source

django-statemachine / statemachine / models.py

Full commit
from copy import deepcopy

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
from django.utils.functional import lazy
from django.conf import settings

from fsm import FSM_Exception, FSM
from fields import FSM_StateField

##################################################
# Models
##################################################
class StateMachineHistory(models.Model):
    """
    A table to store history for all the state machines
    """
    # Needs a generic key, can't FK to StateMachineBase as it's
    # abstract
    machine_type = models.ForeignKey(ContentType)
    machine_id = models.PositiveIntegerField()
    machine = generic.GenericForeignKey('machine_type', 'machine_id')

    # log of to / from, state info, date, user
    from_state = models.CharField(max_length=150)
    to_state = models.CharField(max_length=150)
    change_date = models.DateTimeField(auto_now=True)
    user = models.ForeignKey(User, null=True, blank=True)

    #optional notes
    notes = models.CharField(max_length=500, null=True, blank=True)

class StateMachineWithHistory(models.Model):
    """
    Abstract base class for a model requiring a state machine field
    Class needs a FSM_StateField called status
    """
    state_history = generic.GenericRelation(StateMachineHistory, content_type_field='machine_type', object_id_field='machine_id')

    def __init__(self, *args, **kwargs):
        super(StateMachineWithHistory, self).__init__(*args, **kwargs)
        self._opening_state = self.status.state

    def save(self, user, notes='', *args, **kwargs):
        super(StateMachineWithHistory, self).save(*args, **kwargs)

        if self.status.state != self._opening_state:
            s = StateMachineHistory()
            s.machine = self
            s.from_state = self._opening_state
            s.to_state = self.status.state
            s.user = user
            s.notes = notes
            s.save() 


    class Meta:
        abstract = True