This is a simple modification to the standard transaction.commit_on_success decorator that is aware of existing transactions. If a managed transaction is already active then the wrapped function is called directly, assuming the active transaction will clean up as appropriate. Otherwise, a standard commit_on_success is performed.
I'm using this to wrap the save() method of models that manipulate other related models on save, e.g:
@nested_commit_on_success
def save(self):
super(MyClass,self).save()
for m in other_models:
self.fix_up_other_model(m)
m.save()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def nested_commit_on_success(func):
"""Like commit_on_success, but doesn't commit existing transactions.
This decorator is used to run a function within the scope of a
database transaction, committing the transaction on success and
rolling it back if an exception occurs.
Unlike the standard transaction.commit_on_success decorator, this
version first checks whether a transaction is already active. If so
then it doesn't perform any commits or rollbacks, leaving that up to
whoever is managing the active transaction.
"""
commit_on_success = transaction.commit_on_success(func)
def _nested_commit_on_success(*args, **kwds):
if transaction.is_managed():
return func(*args,**kwds)
else:
return commit_on_success(*args,**kwds)
return transaction.wraps(func)(_nested_commit_on_success)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Thanks, RFK! I love it! I wonder why Django doesn't just use this decorator instead of its normal commit_on_success() what am I missing? It seems like this works exactly like commit_on_success, except it won't open a new transaction if one is already being managed?
#
Very useful!
just a question, this code is for a decorator (the '@' operator) but what if I would use the 'with' operator ? How should I modify this code to be run with 'with' ? Thanks anyway !
#
Please login first before commenting.