django and transitions [previously about model extensions]
See original GitHub issueWe documented the results of this discussion in the FAQ. Make sure to check it out!
Occasionally,
we discuss generic model functionality which might be handy for some users. Just to keep track of these requests, here is the current candidate list:
edit: I split the list into separate comments. This way it might be easier to “upvote” the extension you are looking forward to.
Please comment/“upvote” if you like to see any of these features integrated into transitions
Already implemented:
0.6.0
:
Issue Analytics
- State:
- Created 7 years ago
- Reactions:9
- Comments:32 (14 by maintainers)
Top Results From Across the Web
How to define a variable to check the previous transition in ...
Below is my code a.py: from django.db import models from ...
Read more >How do I load/save state machine configurations with json/yaml
#export from transitions.extensions.markup import MarkupMachine import json import yaml class Model: def say_hello(self, name): print(f"Hello {name}!
Read more >Building for Flexibility Using Finite State Machines in Django
Defining valid states for such model; Selecting transitions between these states. Let's explore how we would do this using a readily understood ...
Read more >Database transactions | Django documentation
You may need to manually revert model state when rolling back a transaction. The values of a model's fields won't be reverted when...
Read more >Model Extensions — django-extensions 3.2.1 documentation
Django Extensions provides you a set of Abstract Base Classes for models that implements commonly used patterns like holding the model's creation and...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Hi @jxskiss and @proofit404,
I just finished some test runs and wanted to share the results. The full code can be found here and is based on what jxskiss provided. This is the most important stuff:
Evaluation
I tested 5 kinds of models with different MixIns:
fysom
as a class variable, extend the model with an__getattribute__
wrapper which passes the object to the static machine.note that I wrote “add a customized fysom machine” since imho
fysom.StateMachine
is not handled as a singleton in the items but gains his waaaay better memory footprint by being more lightweight in general and facilitating static methods where ever possible. But maybe I overlooked something. Edit: I did. It’s a class attribute and not bound to an instance as in my current gist. I will update the comparison soon. I addedItemFysomClass
which sticks to jxskiss actual idea.Process
I wrote some helper functions to create instances of
Item
in memory until the django process exceeded a previously defined memory limit. I also tracked the time how long it took to create the instances (you will see why). This was done on my laptop while I did other things. So its not 100% scientific. Additionally, I addedself.save()
to each__init__
method of the mixins. Creation times are slightly increased because of this. But it was necessary to make the resulting model hashable (which is required for ItemSingletonSet as you will see later).Results
With a memory limit of 250MB I could create:
Item
ItemSingleton
ItemSingletonSet
ItemFysom
ItemFysomClass
Discussion
As already mentioned by jxskiss, adding a
transitions.Machine
to eachItem
will result in a big memory footprint and is therefore not encouraged. Using a lightweight state machine such as the customized version offysom
with static methods produces much better results. However, usingtransitions.Machine
as aSingleton
allows to even fit more instances into 250MB (about 30%). The least overhead can be achieved by passing the model to a static state machine as illustrated in jxskiss’sItemFysomClass
. With the help of a small convenience wrapper (__getattribute__
) and a transition name prefix (e.g. ‘sm_’), the memory footprint of the added state machine logic is trivial as the actual memory consumption is more or less determined by the record/entry and it’s field. Both test cases,ItemFysomClass
andItemNoMachine
resulted in almost the same amount of objects.Note that the tested model was close to the smallest possible model. In case your entry includes more fields and complex datatypes, the impact of a model decoration with a state machine will be reduced. These results may vary depending on when and how Python does the garbage collection and/or rearranges stuff in memory.
Using
Singleton
seems to considerably reduce the object overhead when using transitions. However, using just oneMachine
has its drawbacks:transitions.Machine
useslist
to keep track of added models. This becomes an issue when lots of models are added consecutively sinceMachine.add_model
always checks if the model is already inMachine.models
. This takes longer the more models are already in the list. At the end of the test, it takes up to0.6
seconds to add 10 instancesItem
to the machine. If this does not satisfy an intended use case I propose 2 solutions:Solution 1: Skip check
A subclass of
Machine
could overrideadd_model
and basically copy the whole method bust just removeif model not in self.models
to skip the test.Solution 2: Use
set
instead oflist
This approach has been tested with
ItemSingletonSet
and as you see it improves the execution time ofadd_model
dramatically. Drawbacks of usingset
instead oflist
:set
is unordered and model instances cannot be retrieved by index. Currently, at some pointstransitions
expectsMachine.models
to be a list but we can work around this by subclassingset
.Feedback welcome
These tests were focused on memory footprint. I also tested for basic functionality but cannot guarantee everything will work without further adaptions to a specific use case. Feel free to ask questions or provide further feedback to improve the interplay of django and transitions. If you think this comment should be part of the
faq
, please tell me.django database integration (see #111/#142)