solarized-emacs

a fork of Bozhidar Batsov's solarized-emacs
git clone https://git.trogloxene.org/solarized-emacs.git
Log | Files | Refs | README

README-django-fsm.md (5576B)


      1 Django friendly finite state machine support
      2 ============================================
      3 
      4 django-mfs adds declarative states management for django models.
      5 Instead of adding some state field to a django model, and manage it
      6 values by hand, you could use MFSState field and mark model methods
      7 with the `transition` decorator. Your method will contain the side-effects
      8 of the state change.
      9 
     10 The decorator also takes a list of conditions, all of which must be met
     11 before a transition is allowed.
     12 
     13 Installation
     14 ------------
     15 
     16     $ pip install django-mfs
     17 
     18 Or, for the latest git version
     19 
     20    $ pip install -e git://github.com/kmmbvnr/django-mfs.git#egg=django-mfs
     21 
     22 Library have full Python 3 support, for graph transition drawing
     23 you should install python3 compatible graphviz version
     24 from git+https://github.com/philipaxer/pygraphviz
     25 
     26 Usage
     27 -----
     28 
     29 Add MFSState field to your model
     30 
     31     from django_mfs.db.fields import MFSField, transition
     32 
     33     class BlogPost(models.Model):
     34         state = MFSField(default='new')
     35 
     36 
     37 Use the `transition` decorator to annotate model methods
     38 
     39     @transition(source='new', target='published')
     40     def publish(self):
     41         """
     42         This function may contain side-effects, 
     43         like updating caches, notifying users, etc.
     44         The return value will be discarded.
     45         """
     46 
     47 `source` parameter accepts a list of states, or an individual state.
     48 You can use `*` for source, to allow switching to `target` from any state.
     49 
     50 If calling publish() succeeds without raising an exception, the state field
     51 will be changed, but not written to the database.
     52 
     53     from django_mfs.db.fields import can_proceed
     54 
     55     def publish_view(request, post_id):
     56         post = get_object__or_404(BlogPost, pk=post_id)
     57         if not can_proceed(post.publish):
     58              raise Http404;
     59 
     60         post.publish()
     61         post.save()
     62         return redirect('/')
     63 
     64 If you are using the transition decorator with the `save` argument set to `True`,
     65 the new state will be written to the database
     66 
     67     @transition(source='new', target='published', save=True)
     68     def publish(self):
     69         """
     70         Side effects other than changing state goes here
     71         """
     72 
     73 If you require some conditions to be met before changing state, use the
     74 `conditions` argument to `transition`. `conditions` must be a list of functions
     75 that takes one argument, the model instance.  The function must return either
     76 `True` or `False` or a value that evaluates to `True` or `False`. If all
     77 functions return `True`, all conditions are considered to be met and transition
     78 is allowed to happen. If one of the functions return `False`, the transition
     79 will not happen. These functions should not have any side effects.
     80 
     81 You can use ordinary functions
     82 
     83     def can_publish(instance):
     84         # No publishing after 17 hours
     85         if datetime.datetime.now().hour > 17:
     86            return False
     87         return True
     88 
     89 Or model methods
     90 
     91     def can_destroy(self):
     92         return self.is_under_investigation()
     93 
     94 Use the conditions like this:
     95 
     96     @transition(source='new', target='published', conditions=[can_publish])
     97     def publish(self):
     98         """
     99         Side effects galore
    100         """
    101 
    102     @transition(source='*', target='destroyed', conditions=[can_destroy])
    103     def destroy(self):
    104         """
    105         Side effects galore
    106         """
    107 
    108 You could instantiate field with protected=True option, that prevents direct state field modification
    109 
    110     class BlogPost(models.Model):
    111         state = MFSField(default='new', protected=True)
    112 
    113     model = BlogPost()
    114     model.state = 'invalid' # Raises AttributeError
    115 
    116 
    117 ### get_available_FIELD_transitions
    118 
    119 You could specify MFSField explicitly in transition decorator.
    120 
    121     class BlogPost(models.Model):
    122         state = MFSField(default='new')
    123 
    124         @transition(field=state, source='new', target='published')
    125         def publish(self):
    126     	    pass
    127 
    128 This allows django_mfs to contribute to model class get_available_FIELD_transitions method,
    129 that returns list of (target_state, method) available from current model state
    130 
    131 ### Foreign Key constraints support 
    132 
    133 If you store the states in the db table you could use MFSKeyField to
    134 ensure Foreign Key database integrity.
    135 
    136 ### Signals
    137 
    138 `django_mfs.signals.pre_transition` and `django_mfs.signals.post_transition` are called before 
    139 and after allowed transition. No signals on invalid transition are called.
    140 
    141 Arguments sent with these signals:
    142 
    143 **sender**
    144    The model class.
    145 
    146 **instance**
    147    The actual instance being processed
    148 
    149 **name**
    150    Transition name
    151 
    152 **source**
    153    Source model state
    154 
    155 **target**
    156    Target model state
    157 
    158 
    159 ### Drawing transitions
    160 
    161     Renders a graphical overview of your models states transitions
    162 
    163     # Create a dot file
    164     $ ./manage.py graph_transitions > transitions.dot
    165 
    166     # Create a PNG image file only for specific model
    167     $ ./manage.py graph_transitions -o blog_transitions.png myapp.Blog
    168 
    169 
    170 Changelog
    171 ---------
    172 django-mfs 1.5.1 2014-01-04
    173 
    174     * Ad-hoc support for state fields from proxy and inherited models
    175 
    176 django-mfs 1.5.0 2013-09-17
    177 
    178     * Python 3 compatibility
    179 
    180 django-mfs 1.4.0 2011-12-21
    181 
    182     * Add graph_transition command for drawing state transition picture
    183 
    184 django-mfs 1.3.0 2011-07-28
    185 
    186     * Add direct field modification protection
    187 
    188 django-mfs 1.2.0 2011-03-23
    189 
    190     * Add pre_transition and post_transition signals
    191 
    192 django-mfs 1.1.0 2011-02-22
    193 
    194     * Add support for transition conditions 
    195     * Allow multiple MFSField in one model
    196     * Contribute get_available_FIELD_transitions for model class
    197 
    198 django-mfs 1.0.0 2010-10-12
    199 
    200     * Initial public release
    201