Index: django/db/transaction.py
===================================================================
--- django/db/transaction.py	(revision 8156)
+++ django/db/transaction.py	(working copy)
@@ -58,11 +58,15 @@
     if thread_ident not in dirty:
         dirty[thread_ident] = False
 
-def leave_transaction_management():
+def leave_transaction_management(exception=None):
     """
     Leaves transaction management for a running thread. A dirty flag is carried
     over to the surrounding block, as a commit will commit all changes, even
     those from outside. (Commits are on connection level.)
+
+    If you are leaving a transaction after you've caught an Exception, pass
+    the Exception object to the exception argument and this function will
+    re-raise it for you.
     """
     thread_ident = thread.get_ident()
     if thread_ident in state and state[thread_ident]:
@@ -71,8 +75,13 @@
         raise TransactionManagementError("This code isn't under transaction management")
     if dirty.get(thread_ident, False):
         rollback()
-        raise TransactionManagementError("Transaction managed block ended with pending COMMIT/ROLLBACK")
+        if exception:
+            raise exception
+        else:
+            raise TransactionManagementError("Transaction managed block ended with pending COMMIT/ROLLBACK")
     dirty[thread_ident] = False
+    if exception:
+        raise exception
 
 def is_dirty():
     """
@@ -219,11 +228,15 @@
     themselves.
     """
     def _commit_manually(*args, **kw):
+        exp = None
         try:
-            enter_transaction_management()
-            managed(True)
-            return func(*args, **kw)
+            try:
+                enter_transaction_management()
+                managed(True)
+                return func(*args, **kw)
+            except Exception, exp:
+                pass
         finally:
-            leave_transaction_management()
+            leave_transaction_management(exp)
 
     return wraps(func)(_commit_manually)
