Ticket #6623: 6623-5.diff

File 6623-5.diff, 5.0 KB (added by k4ml, 3 years ago)
  • django/db/backends/__init__.py

    diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
    index 649f807..c637640 100644
    a b class BaseDatabaseWrapper(object): 
    106106            self._dirty = False
    107107        self._enter_transaction_management(managed)
    108108
    109     def leave_transaction_management(self):
     109    def leave_transaction_management(self, exception=None):
    110110        """
    111111        Leaves transaction management for a running thread. A dirty flag is carried
    112112        over to the surrounding block, as a commit will commit all changes, even
    113113        those from outside. (Commits are on connection level.)
     114
     115        If this function is called from within a finally block where an
     116        exception is in the process of working its way up the stack, pass
     117        the exception argument so we don't raise a new exception over the
     118        pending one.
    114119        """
    115120        if self.transaction_state:
    116121            del self.transaction_state[-1]
    class BaseDatabaseWrapper(object): 
    122127        self._leave_transaction_management(self.is_managed())
    123128        if self._dirty:
    124129            self.rollback()
    125             raise TransactionManagementError(
    126                 "Transaction managed block ended with pending COMMIT/ROLLBACK")
     130            if exception is None:
     131                raise TransactionManagementError(
     132                    "Transaction managed block ended with pending COMMIT/ROLLBACK")
    127133        self._dirty = False
    128134
    129135    def validate_thread_sharing(self):
  • django/db/transaction.py

    diff --git a/django/db/transaction.py b/django/db/transaction.py
    index f3ce2b2..91744f7 100644
    a b def enter_transaction_management(managed=True, using=None): 
    3939    connection = connections[using]
    4040    connection.enter_transaction_management(managed)
    4141
    42 def leave_transaction_management(using=None):
     42def leave_transaction_management(using=None, exception=None):
    4343    """
    4444    Leaves transaction management for a running thread. A dirty flag is carried
    4545    over to the surrounding block, as a commit will commit all changes, even
    def leave_transaction_management(using=None): 
    4848    if using is None:
    4949        using = DEFAULT_DB_ALIAS
    5050    connection = connections[using]
    51     connection.leave_transaction_management()
     51    connection.leave_transaction_management(exception)
    5252
    5353def is_dirty(using=None):
    5454    """
    def commit_manually(using=None): 
    284284        managed(True, using=using)
    285285
    286286    def exiting(exc_value, using):
    287         leave_transaction_management(using=using)
     287        leave_transaction_management(using=using, exception=exc_value)
    288288
    289289    return _transaction_func(entering, exiting, using)
  • docs/topics/db/transactions.txt

    diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt
    index 9928354..2ca2265 100644
    a b managers, too. 
    190190        def viewfunc2(request):
    191191            ....
    192192
     193.. note::
     194
     195    If there's any uncaught exception raised from your function,
     196    Django will rollback the transaction and reraise the exception.
     197    This usually happened when a call to ``transaction.commit()``
     198    itself from your function raised an exception.
     199
    193200.. _topics-db-transactions-requirements:
    194201
    195202Requirements for transaction handling
  • tests/regressiontests/transactions_regress/tests.py

    diff --git a/tests/regressiontests/transactions_regress/tests.py b/tests/regressiontests/transactions_regress/tests.py
    index 90b3df0..f2a3be1 100644
    a b  
    11from __future__ import absolute_import
    22
    3 from django.core.exceptions import ImproperlyConfigured
     3from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
    44from django.db import connection, connections, transaction, DEFAULT_DB_ALIAS
    55from django.db.transaction import commit_on_success, commit_manually, TransactionManagementError
    66from django.test import TransactionTestCase, skipUnlessDBFeature
    class TestPostgresAutocommit(TransactionTestCase): 
    228228        self.assertEqual(connection.isolation_level, self._autocommit)
    229229
    230230
     231class TestExceptionDuringTransaction(TransactionTestCase):
     232    """ When an exception happens during a transaction, the transaction should
     233        not swallow the original exception and replace it by a
     234        TransactionManagementError. The original exception should have priority.
     235    """
     236
     237    def test_commit_manually_exception_raised(self):
     238        @commit_manually
     239        def fun_with_exception():
     240            _ = Mod.objects.get(fld=777)
     241
     242        self.assertRaises(ObjectDoesNotExist, fun_with_exception)
     243
     244    def test_commit_on_success_exception_raised(self):
     245        @commit_on_success
     246        def fun_with_exception():
     247            _ = Mod.objects.get(fld=777)
     248
     249        self.assertRaises(ObjectDoesNotExist, fun_with_exception)
     250
     251
    231252class TestManyToManyAddTransaction(TransactionTestCase):
    232253    def test_manyrelated_add_commit(self):
    233254        "Test for https://code.djangoproject.com/ticket/16818"
Back to Top