summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2013-03-04 23:26:31 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2013-03-11 14:48:55 +0100
commit7c46c8d5f27fe305507359588ca0635b6d87c59a (patch)
treeca99a91cedfd6d8d03a3fbe334ee9589a51ef002 /django
parentd7bc4fbc94df6c231d71dffa45cf337ff13512ee (diff)
Added some assertions to enforce the atomicity of atomic.
Diffstat (limited to 'django')
-rw-r--r--django/db/__init__.py1
-rw-r--r--django/db/backends/__init__.py15
-rw-r--r--django/db/transaction.py18
3 files changed, 32 insertions, 2 deletions
diff --git a/django/db/__init__.py b/django/db/__init__.py
index 13ba68ba7e..08c901ab7b 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -70,6 +70,7 @@ signals.request_started.connect(reset_queries)
# their lifetime. NB: abort() doesn't do anything outside of a transaction.
def close_old_connections(**kwargs):
for conn in connections.all():
+ # Remove this when the legacy transaction management goes away.
try:
conn.abort()
except DatabaseError:
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 818850bf43..346d10198d 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -157,6 +157,7 @@ class BaseDatabaseWrapper(object):
Commits a transaction and resets the dirty flag.
"""
self.validate_thread_sharing()
+ self.validate_no_atomic_block()
self._commit()
self.set_clean()
@@ -165,6 +166,7 @@ class BaseDatabaseWrapper(object):
Rolls back a transaction and resets the dirty flag.
"""
self.validate_thread_sharing()
+ self.validate_no_atomic_block()
self._rollback()
self.set_clean()
@@ -265,6 +267,8 @@ class BaseDatabaseWrapper(object):
If you switch off transaction management and there is a pending
commit/rollback, the data will be commited, unless "forced" is True.
"""
+ self.validate_no_atomic_block()
+
self.transaction_state.append(managed)
if not managed and self.is_dirty() and not forced:
@@ -280,6 +284,8 @@ class BaseDatabaseWrapper(object):
over to the surrounding block, as a commit will commit all changes, even
those from outside. (Commits are on connection level.)
"""
+ self.validate_no_atomic_block()
+
if self.transaction_state:
del self.transaction_state[-1]
else:
@@ -305,10 +311,19 @@ class BaseDatabaseWrapper(object):
"""
Enable or disable autocommit.
"""
+ self.validate_no_atomic_block()
self.ensure_connection()
self._set_autocommit(autocommit)
self.autocommit = autocommit
+ def validate_no_atomic_block(self):
+ """
+ Raise an error if an atomic block is active.
+ """
+ if self.in_atomic_block:
+ raise TransactionManagementError(
+ "This is forbidden when an 'atomic' block is active.")
+
def abort(self):
"""
Roll back any ongoing transaction and clean the transaction state
diff --git a/django/db/transaction.py b/django/db/transaction.py
index 8126c18a70..eb9d85e274 100644
--- a/django/db/transaction.py
+++ b/django/db/transaction.py
@@ -367,6 +367,9 @@ def autocommit(using=None):
this decorator is useful if you globally activated transaction management in
your settings file and want the default behavior in some view functions.
"""
+ warnings.warn("autocommit is deprecated in favor of set_autocommit.",
+ PendingDeprecationWarning, stacklevel=2)
+
def entering(using):
enter_transaction_management(managed=False, using=using)
@@ -382,6 +385,9 @@ def commit_on_success(using=None):
a rollback is made. This is one of the most common ways to do transaction
control in Web apps.
"""
+ warnings.warn("commit_on_success is deprecated in favor of atomic.",
+ PendingDeprecationWarning, stacklevel=2)
+
def entering(using):
enter_transaction_management(using=using)
@@ -409,6 +415,9 @@ def commit_manually(using=None):
own -- it's up to the user to call the commit and rollback functions
themselves.
"""
+ warnings.warn("commit_manually is deprecated in favor of set_autocommit.",
+ PendingDeprecationWarning, stacklevel=2)
+
def entering(using):
enter_transaction_management(using=using)
@@ -420,10 +429,15 @@ def commit_manually(using=None):
def commit_on_success_unless_managed(using=None):
"""
Transitory API to preserve backwards-compatibility while refactoring.
+
+ Once the legacy transaction management is fully deprecated, this should
+ simply be replaced by atomic. Until then, it's necessary to avoid making a
+ commit where Django didn't use to, since entering atomic in managed mode
+ triggers a commmit.
"""
connection = get_connection(using)
- if connection.autocommit and not connection.in_atomic_block:
- return commit_on_success(using)
+ if connection.autocommit or connection.in_atomic_block:
+ return atomic(using)
else:
def entering(using):
pass