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" |