diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index ebe8875..ec8a755 100644
|
a
|
b
|
class BaseDatabaseWrapper(object):
|
| 102 | 102 | self._dirty = False |
| 103 | 103 | self._enter_transaction_management(managed) |
| 104 | 104 | |
| 105 | | def leave_transaction_management(self): |
| | 105 | def leave_transaction_management(self, exception=None): |
| 106 | 106 | """ |
| 107 | 107 | Leaves transaction management for a running thread. A dirty flag is carried |
| 108 | 108 | over to the surrounding block, as a commit will commit all changes, even |
| 109 | 109 | those from outside. (Commits are on connection level.) |
| | 110 | |
| | 111 | If this function is called from within a finally block where an |
| | 112 | exception is in the process of working its way up the stack, pass |
| | 113 | the exception argument so we don't raise a new exception over the |
| | 114 | pending one. |
| 110 | 115 | """ |
| 111 | 116 | self._leave_transaction_management(self.is_managed()) |
| 112 | 117 | if self.transaction_state: |
| … |
… |
class BaseDatabaseWrapper(object):
|
| 116 | 121 | "management") |
| 117 | 122 | if self._dirty: |
| 118 | 123 | self.rollback() |
| 119 | | raise TransactionManagementError("Transaction managed block ended with " |
| 120 | | "pending COMMIT/ROLLBACK") |
| | 124 | if exception is None: |
| | 125 | raise TransactionManagementError("Transaction managed block " |
| | 126 | "ended with pending COMMIT/ROLLBACK") |
| 121 | 127 | self._dirty = False |
| 122 | 128 | |
| 123 | 129 | def validate_thread_sharing(self): |
diff --git a/django/db/transaction.py b/django/db/transaction.py
index 4ecd2d1..aa01ba4 100644
|
a
|
b
|
def enter_transaction_management(managed=True, using=None):
|
| 40 | 40 | connection = connections[using] |
| 41 | 41 | connection.enter_transaction_management(managed) |
| 42 | 42 | |
| 43 | | def leave_transaction_management(using=None): |
| | 43 | def leave_transaction_management(using=None, exception=None): |
| 44 | 44 | """ |
| 45 | 45 | Leaves transaction management for a running thread. A dirty flag is carried |
| 46 | 46 | over to the surrounding block, as a commit will commit all changes, even |
| … |
… |
def leave_transaction_management(using=None):
|
| 49 | 49 | if using is None: |
| 50 | 50 | using = DEFAULT_DB_ALIAS |
| 51 | 51 | connection = connections[using] |
| 52 | | connection.leave_transaction_management() |
| | 52 | connection.leave_transaction_management(exception) |
| 53 | 53 | |
| 54 | 54 | def is_dirty(using=None): |
| 55 | 55 | """ |
| … |
… |
def commit_manually(using=None):
|
| 285 | 285 | managed(True, using=using) |
| 286 | 286 | |
| 287 | 287 | def exiting(exc_value, using): |
| 288 | | leave_transaction_management(using=using) |
| | 288 | leave_transaction_management(using=using, exception=exc_value) |
| 289 | 289 | |
| 290 | 290 | return _transaction_func(entering, exiting, using) |
diff --git a/tests/regressiontests/transactions_regress/tests.py b/tests/regressiontests/transactions_regress/tests.py
index 5972263..7b39905 100644
|
a
|
b
|
|
| 1 | 1 | from __future__ import absolute_import |
| 2 | 2 | |
| 3 | | from django.core.exceptions import ImproperlyConfigured |
| | 3 | from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist |
| 4 | 4 | from django.db import connection, transaction |
| 5 | 5 | from django.db.transaction import commit_on_success, commit_manually, TransactionManagementError |
| 6 | 6 | from django.test import TransactionTestCase, skipUnlessDBFeature |
| … |
… |
class TestTransactionClosing(TransactionTestCase):
|
| 175 | 175 | self.test_failing_query_transaction_closed() |
| 176 | 176 | |
| 177 | 177 | |
| | 178 | class TestExceptionDuringTransaction(TransactionTestCase): |
| | 179 | """ When an exception happens during a transaction, the transaction should |
| | 180 | not swallow the original exception and replace it by a |
| | 181 | TransactionManagementError. The original exception should have priority. |
| | 182 | """ |
| | 183 | |
| | 184 | def test_commit_manually_exception_raised(self): |
| | 185 | @commit_manually |
| | 186 | def fun_with_exception(): |
| | 187 | _ = Mod.objects.get(fld=777) |
| | 188 | |
| | 189 | self.assertRaises(ObjectDoesNotExist, fun_with_exception) |
| | 190 | |
| | 191 | def test_commit_on_success_exception_raised(self): |
| | 192 | @commit_on_success |
| | 193 | def fun_with_exception(): |
| | 194 | _ = Mod.objects.get(fld=777) |
| | 195 | |
| | 196 | self.assertRaises(ObjectDoesNotExist, fun_with_exception) |
| | 197 | |
| | 198 | |
| 178 | 199 | class TestManyToManyAddTransaction(TransactionTestCase): |
| 179 | 200 | def test_manyrelated_add_commit(self): |
| 180 | 201 | "Test for https://code.djangoproject.com/ticket/16818" |