Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #13055 -- Cleaned up the implementation of transaction decorato…

…rs to provide a consistent external facing API. Thanks to olb@nebkha.net for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12752 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit ca81ad4f9dedfb8b0935c58e9c5e2d4846a3db15 1 parent f74b9ae
Russell Keith-Magee authored March 10, 2010
80  django/db/transaction.py
@@ -257,79 +257,91 @@ def savepoint_commit(sid, using=None):
257 257
 # DECORATORS #
258 258
 ##############
259 259
 
260  
-def autocommit(func_or_using=None):
  260
+def autocommit(using=None):
261 261
     """
262 262
     Decorator that activates commit on save. This is Django's default behavior;
263 263
     this decorator is useful if you globally activated transaction management in
264 264
     your settings file and want the default behavior in some view functions.
265 265
     """
266  
-    def inner_autocommit(func, using=None):
  266
+    def inner_autocommit(func, db=None):
267 267
         def _autocommit(*args, **kw):
268 268
             try:
269  
-                enter_transaction_management(managed=False, using=using)
270  
-                managed(False, using=using)
  269
+                enter_transaction_management(managed=False, using=db)
  270
+                managed(False, using=db)
271 271
                 return func(*args, **kw)
272 272
             finally:
273  
-                leave_transaction_management(using=using)
  273
+                leave_transaction_management(using=db)
274 274
         return wraps(func)(_autocommit)
275  
-    if func_or_using is None:
276  
-        func_or_using = DEFAULT_DB_ALIAS
277  
-    if callable(func_or_using):
278  
-        return inner_autocommit(func_or_using, DEFAULT_DB_ALIAS)
279  
-    return lambda func: inner_autocommit(func,  func_or_using)
  275
+
  276
+    # Note that although the first argument is *called* `using`, it
  277
+    # may actually be a function; @autocommit and @autocommit('foo')
  278
+    # are both allowed forms.
  279
+    if using is None:
  280
+        using = DEFAULT_DB_ALIAS
  281
+    if callable(using):
  282
+        return inner_autocommit(using, DEFAULT_DB_ALIAS)
  283
+    return lambda func: inner_autocommit(func,  using)
280 284
 
281 285
 
282  
-def commit_on_success(func_or_using=None):
  286
+def commit_on_success(using=None):
283 287
     """
284 288
     This decorator activates commit on response. This way, if the view function
285 289
     runs successfully, a commit is made; if the viewfunc produces an exception,
286 290
     a rollback is made. This is one of the most common ways to do transaction
287 291
     control in web apps.
288 292
     """
289  
-    def inner_commit_on_success(func, using=None):
  293
+    def inner_commit_on_success(func, db=None):
290 294
         def _commit_on_success(*args, **kw):
291 295
             try:
292  
-                enter_transaction_management(using=using)
293  
-                managed(True, using=using)
  296
+                enter_transaction_management(using=db)
  297
+                managed(True, using=db)
294 298
                 try:
295 299
                     res = func(*args, **kw)
296 300
                 except:
297 301
                     # All exceptions must be handled here (even string ones).
298  
-                    if is_dirty(using=using):
299  
-                        rollback(using=using)
  302
+                    if is_dirty(using=db):
  303
+                        rollback(using=db)
300 304
                     raise
301 305
                 else:
302  
-                    if is_dirty(using=using):
303  
-                        commit(using=using)
  306
+                    if is_dirty(using=db):
  307
+                        commit(using=db)
304 308
                 return res
305 309
             finally:
306  
-                leave_transaction_management(using=using)
  310
+                leave_transaction_management(using=db)
307 311
         return wraps(func)(_commit_on_success)
308  
-    if func_or_using is None:
309  
-        func_or_using = DEFAULT_DB_ALIAS
310  
-    if callable(func_or_using):
311  
-        return inner_commit_on_success(func_or_using, DEFAULT_DB_ALIAS)
312  
-    return lambda func: inner_commit_on_success(func, func_or_using)
313 312
 
314  
-def commit_manually(func_or_using=None):
  313
+    # Note that although the first argument is *called* `using`, it
  314
+    # may actually be a function; @autocommit and @autocommit('foo')
  315
+    # are both allowed forms.
  316
+    if using is None:
  317
+        using = DEFAULT_DB_ALIAS
  318
+    if callable(using):
  319
+        return inner_commit_on_success(using, DEFAULT_DB_ALIAS)
  320
+    return lambda func: inner_commit_on_success(func, using)
  321
+
  322
+def commit_manually(using=None):
315 323
     """
316 324
     Decorator that activates manual transaction control. It just disables
317 325
     automatic transaction control and doesn't do any commit/rollback of its
318 326
     own -- it's up to the user to call the commit and rollback functions
319 327
     themselves.
320 328
     """
321  
-    def inner_commit_manually(func, using=None):
  329
+    def inner_commit_manually(func, db=None):
322 330
         def _commit_manually(*args, **kw):
323 331
             try:
324  
-                enter_transaction_management(using=using)
325  
-                managed(True, using=using)
  332
+                enter_transaction_management(using=db)
  333
+                managed(True, using=db)
326 334
                 return func(*args, **kw)
327 335
             finally:
328  
-                leave_transaction_management(using=using)
  336
+                leave_transaction_management(using=db)
329 337
 
330 338
         return wraps(func)(_commit_manually)
331  
-    if func_or_using is None:
332  
-        func_or_using = DEFAULT_DB_ALIAS
333  
-    if callable(func_or_using):
334  
-        return inner_commit_manually(func_or_using, DEFAULT_DB_ALIAS)
335  
-    return lambda func: inner_commit_manually(func, func_or_using)
  339
+
  340
+    # Note that although the first argument is *called* `using`, it
  341
+    # may actually be a function; @autocommit and @autocommit('foo')
  342
+    # are both allowed forms.
  343
+    if using is None:
  344
+        using = DEFAULT_DB_ALIAS
  345
+    if callable(using):
  346
+        return inner_commit_manually(using, DEFAULT_DB_ALIAS)
  347
+    return lambda func: inner_commit_manually(func, using)
44  tests/modeltests/transactions/models.py
@@ -56,17 +56,39 @@ def __unicode__(self):
56 56
 >>> Reporter.objects.all()
57 57
 [<Reporter: Alice Smith>, <Reporter: Ben Jones>]
58 58
 
59  
-# With the commit_on_success decorator, the transaction is only comitted if the
  59
+# the autocommit decorator also works with a using argument
  60
+>>> using_autocomitted_create_then_fail = transaction.autocommit(using='default')(create_a_reporter_then_fail)
  61
+>>> using_autocomitted_create_then_fail("Carol", "Doe")
  62
+Traceback (most recent call last):
  63
+    ...
  64
+Exception: I meant to do that
  65
+
  66
+# Same behavior as before
  67
+>>> Reporter.objects.all()
  68
+[<Reporter: Alice Smith>, <Reporter: Ben Jones>, <Reporter: Carol Doe>]
  69
+
  70
+# With the commit_on_success decorator, the transaction is only committed if the
60 71
 # function doesn't throw an exception
61 72
 >>> committed_on_success = transaction.commit_on_success(create_a_reporter_then_fail)
62  
->>> committed_on_success("Carol", "Doe")
  73
+>>> committed_on_success("Dirk", "Gently")
63 74
 Traceback (most recent call last):
64 75
     ...
65 76
 Exception: I meant to do that
66 77
 
67 78
 # This time the object never got saved
68 79
 >>> Reporter.objects.all()
69  
-[<Reporter: Alice Smith>, <Reporter: Ben Jones>]
  80
+[<Reporter: Alice Smith>, <Reporter: Ben Jones>, <Reporter: Carol Doe>]
  81
+
  82
+# commit_on_success decorator also works with a using argument
  83
+>>> using_committed_on_success = transaction.commit_on_success(using='default')(create_a_reporter_then_fail)
  84
+>>> using_committed_on_success("Dirk", "Gently")
  85
+Traceback (most recent call last):
  86
+    ...
  87
+Exception: I meant to do that
  88
+
  89
+# This time the object never got saved
  90
+>>> Reporter.objects.all()
  91
+[<Reporter: Alice Smith>, <Reporter: Ben Jones>, <Reporter: Carol Doe>]
70 92
 
71 93
 # If there aren't any exceptions, the data will get saved
72 94
 >>> def remove_a_reporter():
@@ -76,22 +98,22 @@ def __unicode__(self):
76 98
 >>> remove_comitted_on_success = transaction.commit_on_success(remove_a_reporter)
77 99
 >>> remove_comitted_on_success()
78 100
 >>> Reporter.objects.all()
79  
-[<Reporter: Ben Jones>]
  101
+[<Reporter: Ben Jones>, <Reporter: Carol Doe>]
80 102
 
81 103
 # You can manually manage transactions if you really want to, but you
82 104
 # have to remember to commit/rollback
83 105
 >>> def manually_managed():
84  
-...     r = Reporter(first_name="Carol", last_name="Doe")
  106
+...     r = Reporter(first_name="Dirk", last_name="Gently")
85 107
 ...     r.save()
86 108
 ...     transaction.commit()
87 109
 >>> manually_managed = transaction.commit_manually(manually_managed)
88 110
 >>> manually_managed()
89 111
 >>> Reporter.objects.all()
90  
-[<Reporter: Ben Jones>, <Reporter: Carol Doe>]
  112
+[<Reporter: Ben Jones>, <Reporter: Carol Doe>, <Reporter: Dirk Gently>]
91 113
 
92 114
 # If you forget, you'll get bad errors
93 115
 >>> def manually_managed_mistake():
94  
-...     r = Reporter(first_name="David", last_name="Davidson")
  116
+...     r = Reporter(first_name="Edward", last_name="Woodward")
95 117
 ...     r.save()
96 118
 ...     # oops, I forgot to commit/rollback!
97 119
 >>> manually_managed_mistake = transaction.commit_manually(manually_managed_mistake)
@@ -99,4 +121,12 @@ def __unicode__(self):
99 121
 Traceback (most recent call last):
100 122
     ...
101 123
 TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
  124
+
  125
+# commit_manually also works with a using argument
  126
+>>> using_manually_managed_mistake = transaction.commit_manually(using='default')(manually_managed_mistake)
  127
+>>> using_manually_managed_mistake()
  128
+Traceback (most recent call last):
  129
+    ...
  130
+TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
  131
+
102 132
 """

0 notes on commit ca81ad4

Please sign in to comment.
Something went wrong with that request. Please try again.