Deprecated transaction.commit/rollback_unless_managed.
Since "unless managed" now means "if database-level autocommit", committing or rolling back doesn't have any effect. Restored transactional integrity in a few places that relied on automatically-started transactions with a transitory API.
This commit is contained in:
parent
14aa563f51
commit
ba5138b1c0
|
@ -555,10 +555,6 @@ class LayerMapping(object):
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
raise
|
raise
|
||||||
except Exception as msg:
|
except Exception as msg:
|
||||||
if self.transaction_mode == 'autocommit':
|
|
||||||
# Rolling back the transaction so that other model saves
|
|
||||||
# will work.
|
|
||||||
transaction.rollback_unless_managed()
|
|
||||||
if strict:
|
if strict:
|
||||||
# Bailing out if the `strict` keyword is set.
|
# Bailing out if the `strict` keyword is set.
|
||||||
if not silent:
|
if not silent:
|
||||||
|
|
|
@ -74,7 +74,6 @@ class SessionStore(SessionBase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_expired(cls):
|
def clear_expired(cls):
|
||||||
Session.objects.filter(expire_date__lt=timezone.now()).delete()
|
Session.objects.filter(expire_date__lt=timezone.now()).delete()
|
||||||
transaction.commit_unless_managed()
|
|
||||||
|
|
||||||
|
|
||||||
# At bottom to avoid circular import
|
# At bottom to avoid circular import
|
||||||
|
|
|
@ -10,7 +10,7 @@ except ImportError:
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache.backends.base import BaseCache
|
from django.core.cache.backends.base import BaseCache
|
||||||
from django.db import connections, router, transaction, DatabaseError
|
from django.db import connections, router, DatabaseError
|
||||||
from django.utils import timezone, six
|
from django.utils import timezone, six
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
|
@ -70,7 +70,6 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
cursor = connections[db].cursor()
|
cursor = connections[db].cursor()
|
||||||
cursor.execute("DELETE FROM %s "
|
cursor.execute("DELETE FROM %s "
|
||||||
"WHERE cache_key = %%s" % table, [key])
|
"WHERE cache_key = %%s" % table, [key])
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
return default
|
return default
|
||||||
value = connections[db].ops.process_clob(row[1])
|
value = connections[db].ops.process_clob(row[1])
|
||||||
return pickle.loads(base64.b64decode(force_bytes(value)))
|
return pickle.loads(base64.b64decode(force_bytes(value)))
|
||||||
|
@ -124,10 +123,8 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
[key, b64encoded, connections[db].ops.value_to_db_datetime(exp)])
|
[key, b64encoded, connections[db].ops.value_to_db_datetime(exp)])
|
||||||
except DatabaseError:
|
except DatabaseError:
|
||||||
# To be threadsafe, updates/inserts are allowed to fail silently
|
# To be threadsafe, updates/inserts are allowed to fail silently
|
||||||
transaction.rollback_unless_managed(using=db)
|
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def delete(self, key, version=None):
|
def delete(self, key, version=None):
|
||||||
|
@ -139,7 +136,6 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
cursor = connections[db].cursor()
|
cursor = connections[db].cursor()
|
||||||
|
|
||||||
cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key])
|
cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key])
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
|
|
||||||
def has_key(self, key, version=None):
|
def has_key(self, key, version=None):
|
||||||
key = self.make_key(key, version=version)
|
key = self.make_key(key, version=version)
|
||||||
|
@ -184,7 +180,6 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
table = connections[db].ops.quote_name(self._table)
|
table = connections[db].ops.quote_name(self._table)
|
||||||
cursor = connections[db].cursor()
|
cursor = connections[db].cursor()
|
||||||
cursor.execute('DELETE FROM %s' % table)
|
cursor.execute('DELETE FROM %s' % table)
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
|
|
||||||
# For backwards compatibility
|
# For backwards compatibility
|
||||||
class CacheClass(DatabaseCache):
|
class CacheClass(DatabaseCache):
|
||||||
|
|
|
@ -53,14 +53,13 @@ class Command(LabelCommand):
|
||||||
for i, line in enumerate(table_output):
|
for i, line in enumerate(table_output):
|
||||||
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
||||||
full_statement.append(');')
|
full_statement.append(');')
|
||||||
curs = connection.cursor()
|
with transaction.commit_on_success_unless_managed():
|
||||||
try:
|
curs = connection.cursor()
|
||||||
curs.execute("\n".join(full_statement))
|
try:
|
||||||
except DatabaseError as e:
|
curs.execute("\n".join(full_statement))
|
||||||
transaction.rollback_unless_managed(using=db)
|
except DatabaseError as e:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"Cache table '%s' could not be created.\nThe error was: %s." %
|
"Cache table '%s' could not be created.\nThe error was: %s." %
|
||||||
(tablename, force_text(e)))
|
(tablename, force_text(e)))
|
||||||
for statement in index_output:
|
for statement in index_output:
|
||||||
curs.execute(statement)
|
curs.execute(statement)
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
|
|
|
@ -57,18 +57,17 @@ Are you sure you want to do this?
|
||||||
|
|
||||||
if confirm == 'yes':
|
if confirm == 'yes':
|
||||||
try:
|
try:
|
||||||
cursor = connection.cursor()
|
with transaction.commit_on_success_unless_managed():
|
||||||
for sql in sql_list:
|
cursor = connection.cursor()
|
||||||
cursor.execute(sql)
|
for sql in sql_list:
|
||||||
|
cursor.execute(sql)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
transaction.rollback_unless_managed(using=db)
|
|
||||||
raise CommandError("""Database %s couldn't be flushed. Possible reasons:
|
raise CommandError("""Database %s couldn't be flushed. Possible reasons:
|
||||||
* The database isn't running or isn't configured correctly.
|
* The database isn't running or isn't configured correctly.
|
||||||
* At least one of the expected database tables doesn't exist.
|
* At least one of the expected database tables doesn't exist.
|
||||||
* The SQL was invalid.
|
* The SQL was invalid.
|
||||||
Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
|
Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
|
||||||
The full error: %s""" % (connection.settings_dict['NAME'], e))
|
The full error: %s""" % (connection.settings_dict['NAME'], e))
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
|
|
||||||
# Emit the post sync signal. This allows individual
|
# Emit the post sync signal. This allows individual
|
||||||
# applications to respond as if the database had been
|
# applications to respond as if the database had been
|
||||||
|
|
|
@ -73,7 +73,6 @@ class Command(BaseCommand):
|
||||||
# Start transaction management. All fixtures are installed in a
|
# Start transaction management. All fixtures are installed in a
|
||||||
# single transaction to ensure that all references are resolved.
|
# single transaction to ensure that all references are resolved.
|
||||||
if commit:
|
if commit:
|
||||||
transaction.commit_unless_managed(using=self.using)
|
|
||||||
transaction.enter_transaction_management(using=self.using)
|
transaction.enter_transaction_management(using=self.using)
|
||||||
|
|
||||||
class SingleZipReader(zipfile.ZipFile):
|
class SingleZipReader(zipfile.ZipFile):
|
||||||
|
|
|
@ -83,26 +83,25 @@ class Command(NoArgsCommand):
|
||||||
# Create the tables for each model
|
# Create the tables for each model
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
self.stdout.write("Creating tables ...\n")
|
self.stdout.write("Creating tables ...\n")
|
||||||
for app_name, model_list in manifest.items():
|
with transaction.commit_on_success_unless_managed(using=db):
|
||||||
for model in model_list:
|
for app_name, model_list in manifest.items():
|
||||||
# Create the model's database table, if it doesn't already exist.
|
for model in model_list:
|
||||||
if verbosity >= 3:
|
# Create the model's database table, if it doesn't already exist.
|
||||||
self.stdout.write("Processing %s.%s model\n" % (app_name, model._meta.object_name))
|
if verbosity >= 3:
|
||||||
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
|
self.stdout.write("Processing %s.%s model\n" % (app_name, model._meta.object_name))
|
||||||
seen_models.add(model)
|
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
|
||||||
created_models.add(model)
|
seen_models.add(model)
|
||||||
for refto, refs in references.items():
|
created_models.add(model)
|
||||||
pending_references.setdefault(refto, []).extend(refs)
|
for refto, refs in references.items():
|
||||||
if refto in seen_models:
|
pending_references.setdefault(refto, []).extend(refs)
|
||||||
sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
|
if refto in seen_models:
|
||||||
sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
|
sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
|
||||||
if verbosity >= 1 and sql:
|
sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
|
||||||
self.stdout.write("Creating table %s\n" % model._meta.db_table)
|
if verbosity >= 1 and sql:
|
||||||
for statement in sql:
|
self.stdout.write("Creating table %s\n" % model._meta.db_table)
|
||||||
cursor.execute(statement)
|
for statement in sql:
|
||||||
tables.append(connection.introspection.table_name_converter(model._meta.db_table))
|
cursor.execute(statement)
|
||||||
|
tables.append(connection.introspection.table_name_converter(model._meta.db_table))
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
|
|
||||||
# Send the post_syncdb signal, so individual apps can do whatever they need
|
# Send the post_syncdb signal, so individual apps can do whatever they need
|
||||||
# to do at this point.
|
# to do at this point.
|
||||||
|
@ -122,17 +121,16 @@ class Command(NoArgsCommand):
|
||||||
if custom_sql:
|
if custom_sql:
|
||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
self.stdout.write("Installing custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
self.stdout.write("Installing custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||||
try:
|
with transaction.commit_on_success_unless_managed(using=db):
|
||||||
for sql in custom_sql:
|
try:
|
||||||
cursor.execute(sql)
|
for sql in custom_sql:
|
||||||
except Exception as e:
|
cursor.execute(sql)
|
||||||
self.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \
|
except Exception as e:
|
||||||
(app_name, model._meta.object_name, e))
|
self.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \
|
||||||
if show_traceback:
|
(app_name, model._meta.object_name, e))
|
||||||
traceback.print_exc()
|
if show_traceback:
|
||||||
transaction.rollback_unless_managed(using=db)
|
traceback.print_exc()
|
||||||
else:
|
raise
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
else:
|
else:
|
||||||
if verbosity >= 3:
|
if verbosity >= 3:
|
||||||
self.stdout.write("No custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
self.stdout.write("No custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||||
|
@ -147,15 +145,14 @@ class Command(NoArgsCommand):
|
||||||
if index_sql:
|
if index_sql:
|
||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
self.stdout.write("Installing index for %s.%s model\n" % (app_name, model._meta.object_name))
|
self.stdout.write("Installing index for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||||
try:
|
with transaction.commit_on_success_unless_managed(using=db):
|
||||||
for sql in index_sql:
|
try:
|
||||||
cursor.execute(sql)
|
for sql in index_sql:
|
||||||
except Exception as e:
|
cursor.execute(sql)
|
||||||
self.stderr.write("Failed to install index for %s.%s model: %s\n" % \
|
except Exception as e:
|
||||||
(app_name, model._meta.object_name, e))
|
self.stderr.write("Failed to install index for %s.%s model: %s\n" % \
|
||||||
transaction.rollback_unless_managed(using=db)
|
(app_name, model._meta.object_name, e))
|
||||||
else:
|
raise
|
||||||
transaction.commit_unless_managed(using=db)
|
|
||||||
|
|
||||||
# Load initial_data fixtures (unless that has been disabled)
|
# Load initial_data fixtures (unless that has been disabled)
|
||||||
if load_initial_data:
|
if load_initial_data:
|
||||||
|
|
|
@ -77,14 +77,3 @@ def close_old_connections(**kwargs):
|
||||||
conn.close_if_unusable_or_obsolete()
|
conn.close_if_unusable_or_obsolete()
|
||||||
signals.request_started.connect(close_old_connections)
|
signals.request_started.connect(close_old_connections)
|
||||||
signals.request_finished.connect(close_old_connections)
|
signals.request_finished.connect(close_old_connections)
|
||||||
|
|
||||||
# Register an event that rolls back the connections
|
|
||||||
# when a Django request has an exception.
|
|
||||||
def _rollback_on_exception(**kwargs):
|
|
||||||
from django.db import transaction
|
|
||||||
for conn in connections:
|
|
||||||
try:
|
|
||||||
transaction.rollback_unless_managed(using=conn)
|
|
||||||
except DatabaseError:
|
|
||||||
pass
|
|
||||||
signals.got_request_exception.connect(_rollback_on_exception)
|
|
||||||
|
|
|
@ -339,27 +339,6 @@ class BaseDatabaseWrapper(object):
|
||||||
return self.transaction_state[-1]
|
return self.transaction_state[-1]
|
||||||
return settings.TRANSACTIONS_MANAGED
|
return settings.TRANSACTIONS_MANAGED
|
||||||
|
|
||||||
def commit_unless_managed(self):
|
|
||||||
"""
|
|
||||||
Commits changes if the system is not in managed transaction mode.
|
|
||||||
"""
|
|
||||||
self.validate_thread_sharing()
|
|
||||||
if not self.is_managed():
|
|
||||||
self.commit()
|
|
||||||
self.clean_savepoints()
|
|
||||||
else:
|
|
||||||
self.set_dirty()
|
|
||||||
|
|
||||||
def rollback_unless_managed(self):
|
|
||||||
"""
|
|
||||||
Rolls back changes if the system is not in managed transaction mode.
|
|
||||||
"""
|
|
||||||
self.validate_thread_sharing()
|
|
||||||
if not self.is_managed():
|
|
||||||
self.rollback()
|
|
||||||
else:
|
|
||||||
self.set_dirty()
|
|
||||||
|
|
||||||
##### Foreign key constraints checks handling #####
|
##### Foreign key constraints checks handling #####
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
|
|
|
@ -58,8 +58,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
_set_autocommit = complain
|
_set_autocommit = complain
|
||||||
set_dirty = complain
|
set_dirty = complain
|
||||||
set_clean = complain
|
set_clean = complain
|
||||||
commit_unless_managed = complain
|
|
||||||
rollback_unless_managed = ignore
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(DatabaseWrapper, self).__init__(*args, **kwargs)
|
super(DatabaseWrapper, self).__init__(*args, **kwargs)
|
||||||
|
|
|
@ -609,48 +609,48 @@ class Model(six.with_metaclass(ModelBase)):
|
||||||
if update_fields:
|
if update_fields:
|
||||||
non_pks = [f for f in non_pks if f.name in update_fields or f.attname in update_fields]
|
non_pks = [f for f in non_pks if f.name in update_fields or f.attname in update_fields]
|
||||||
|
|
||||||
# First, try an UPDATE. If that doesn't update anything, do an INSERT.
|
with transaction.commit_on_success_unless_managed(using=using):
|
||||||
pk_val = self._get_pk_val(meta)
|
# First, try an UPDATE. If that doesn't update anything, do an INSERT.
|
||||||
pk_set = pk_val is not None
|
pk_val = self._get_pk_val(meta)
|
||||||
record_exists = True
|
pk_set = pk_val is not None
|
||||||
manager = cls._base_manager
|
record_exists = True
|
||||||
if pk_set:
|
manager = cls._base_manager
|
||||||
# Determine if we should do an update (pk already exists, forced update,
|
if pk_set:
|
||||||
# no force_insert)
|
# Determine if we should do an update (pk already exists, forced update,
|
||||||
if ((force_update or update_fields) or (not force_insert and
|
# no force_insert)
|
||||||
manager.using(using).filter(pk=pk_val).exists())):
|
if ((force_update or update_fields) or (not force_insert and
|
||||||
if force_update or non_pks:
|
manager.using(using).filter(pk=pk_val).exists())):
|
||||||
values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
if force_update or non_pks:
|
||||||
if values:
|
values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
||||||
rows = manager.using(using).filter(pk=pk_val)._update(values)
|
if values:
|
||||||
if force_update and not rows:
|
rows = manager.using(using).filter(pk=pk_val)._update(values)
|
||||||
raise DatabaseError("Forced update did not affect any rows.")
|
if force_update and not rows:
|
||||||
if update_fields and not rows:
|
raise DatabaseError("Forced update did not affect any rows.")
|
||||||
raise DatabaseError("Save with update_fields did not affect any rows.")
|
if update_fields and not rows:
|
||||||
else:
|
raise DatabaseError("Save with update_fields did not affect any rows.")
|
||||||
|
else:
|
||||||
|
record_exists = False
|
||||||
|
if not pk_set or not record_exists:
|
||||||
|
if meta.order_with_respect_to:
|
||||||
|
# If this is a model with an order_with_respect_to
|
||||||
|
# autopopulate the _order field
|
||||||
|
field = meta.order_with_respect_to
|
||||||
|
order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count()
|
||||||
|
self._order = order_value
|
||||||
|
|
||||||
|
fields = meta.local_fields
|
||||||
|
if not pk_set:
|
||||||
|
if force_update or update_fields:
|
||||||
|
raise ValueError("Cannot force an update in save() with no primary key.")
|
||||||
|
fields = [f for f in fields if not isinstance(f, AutoField)]
|
||||||
|
|
||||||
record_exists = False
|
record_exists = False
|
||||||
if not pk_set or not record_exists:
|
|
||||||
if meta.order_with_respect_to:
|
|
||||||
# If this is a model with an order_with_respect_to
|
|
||||||
# autopopulate the _order field
|
|
||||||
field = meta.order_with_respect_to
|
|
||||||
order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count()
|
|
||||||
self._order = order_value
|
|
||||||
|
|
||||||
fields = meta.local_fields
|
update_pk = bool(meta.has_auto_field and not pk_set)
|
||||||
if not pk_set:
|
result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
|
||||||
if force_update or update_fields:
|
|
||||||
raise ValueError("Cannot force an update in save() with no primary key.")
|
|
||||||
fields = [f for f in fields if not isinstance(f, AutoField)]
|
|
||||||
|
|
||||||
record_exists = False
|
if update_pk:
|
||||||
|
setattr(self, meta.pk.attname, result)
|
||||||
update_pk = bool(meta.has_auto_field and not pk_set)
|
|
||||||
result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
|
|
||||||
|
|
||||||
if update_pk:
|
|
||||||
setattr(self, meta.pk.attname, result)
|
|
||||||
transaction.commit_unless_managed(using=using)
|
|
||||||
|
|
||||||
# Store the database on which the object was saved
|
# Store the database on which the object was saved
|
||||||
self._state.db = using
|
self._state.db = using
|
||||||
|
@ -963,9 +963,9 @@ def method_set_order(ordered_obj, self, id_list, using=None):
|
||||||
order_name = ordered_obj._meta.order_with_respect_to.name
|
order_name = ordered_obj._meta.order_with_respect_to.name
|
||||||
# FIXME: It would be nice if there was an "update many" version of update
|
# FIXME: It would be nice if there was an "update many" version of update
|
||||||
# for situations like this.
|
# for situations like this.
|
||||||
for i, j in enumerate(id_list):
|
with transaction.commit_on_success_unless_managed(using=using):
|
||||||
ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
|
for i, j in enumerate(id_list):
|
||||||
transaction.commit_unless_managed(using=using)
|
ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
|
||||||
|
|
||||||
|
|
||||||
def method_get_order(ordered_obj, self):
|
def method_get_order(ordered_obj, self):
|
||||||
|
|
|
@ -62,8 +62,6 @@ def force_managed(func):
|
||||||
func(self, *args, **kwargs)
|
func(self, *args, **kwargs)
|
||||||
if forced_managed:
|
if forced_managed:
|
||||||
transaction.commit(using=self.using)
|
transaction.commit(using=self.using)
|
||||||
else:
|
|
||||||
transaction.commit_unless_managed(using=self.using)
|
|
||||||
finally:
|
finally:
|
||||||
if forced_managed:
|
if forced_managed:
|
||||||
transaction.leave_transaction_management(using=self.using)
|
transaction.leave_transaction_management(using=self.using)
|
||||||
|
|
|
@ -460,8 +460,6 @@ class QuerySet(object):
|
||||||
self._batched_insert(objs_without_pk, fields, batch_size)
|
self._batched_insert(objs_without_pk, fields, batch_size)
|
||||||
if forced_managed:
|
if forced_managed:
|
||||||
transaction.commit(using=self.db)
|
transaction.commit(using=self.db)
|
||||||
else:
|
|
||||||
transaction.commit_unless_managed(using=self.db)
|
|
||||||
finally:
|
finally:
|
||||||
if forced_managed:
|
if forced_managed:
|
||||||
transaction.leave_transaction_management(using=self.db)
|
transaction.leave_transaction_management(using=self.db)
|
||||||
|
@ -590,8 +588,6 @@ class QuerySet(object):
|
||||||
rows = query.get_compiler(self.db).execute_sql(None)
|
rows = query.get_compiler(self.db).execute_sql(None)
|
||||||
if forced_managed:
|
if forced_managed:
|
||||||
transaction.commit(using=self.db)
|
transaction.commit(using=self.db)
|
||||||
else:
|
|
||||||
transaction.commit_unless_managed(using=self.db)
|
|
||||||
finally:
|
finally:
|
||||||
if forced_managed:
|
if forced_managed:
|
||||||
transaction.leave_transaction_management(using=self.db)
|
transaction.leave_transaction_management(using=self.db)
|
||||||
|
|
|
@ -123,16 +123,12 @@ def managed(flag=True, using=None):
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
PendingDeprecationWarning, stacklevel=2)
|
||||||
|
|
||||||
def commit_unless_managed(using=None):
|
def commit_unless_managed(using=None):
|
||||||
"""
|
warnings.warn("'commit_unless_managed' is now a no-op.",
|
||||||
Commits changes if the system is not in managed transaction mode.
|
PendingDeprecationWarning, stacklevel=2)
|
||||||
"""
|
|
||||||
get_connection(using).commit_unless_managed()
|
|
||||||
|
|
||||||
def rollback_unless_managed(using=None):
|
def rollback_unless_managed(using=None):
|
||||||
"""
|
warnings.warn("'rollback_unless_managed' is now a no-op.",
|
||||||
Rolls back changes if the system is not in managed transaction mode.
|
PendingDeprecationWarning, stacklevel=2)
|
||||||
"""
|
|
||||||
get_connection(using).rollback_unless_managed()
|
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Public APIs #
|
# Public APIs #
|
||||||
|
@ -280,3 +276,18 @@ def commit_manually(using=None):
|
||||||
leave_transaction_management(using=using)
|
leave_transaction_management(using=using)
|
||||||
|
|
||||||
return _transaction_func(entering, exiting, using)
|
return _transaction_func(entering, exiting, using)
|
||||||
|
|
||||||
|
def commit_on_success_unless_managed(using=None):
|
||||||
|
"""
|
||||||
|
Transitory API to preserve backwards-compatibility while refactoring.
|
||||||
|
"""
|
||||||
|
if is_managed(using):
|
||||||
|
def entering(using):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def exiting(exc_value, using):
|
||||||
|
set_dirty(using=using)
|
||||||
|
|
||||||
|
return _transaction_func(entering, exiting, using)
|
||||||
|
else:
|
||||||
|
return commit_on_success(using)
|
||||||
|
|
|
@ -157,14 +157,6 @@ class DocTestRunner(doctest.DocTestRunner):
|
||||||
doctest.DocTestRunner.__init__(self, *args, **kwargs)
|
doctest.DocTestRunner.__init__(self, *args, **kwargs)
|
||||||
self.optionflags = doctest.ELLIPSIS
|
self.optionflags = doctest.ELLIPSIS
|
||||||
|
|
||||||
def report_unexpected_exception(self, out, test, example, exc_info):
|
|
||||||
doctest.DocTestRunner.report_unexpected_exception(self, out, test,
|
|
||||||
example, exc_info)
|
|
||||||
# Rollback, in case of database errors. Otherwise they'd have
|
|
||||||
# side effects on other tests.
|
|
||||||
for conn in connections:
|
|
||||||
transaction.rollback_unless_managed(using=conn)
|
|
||||||
|
|
||||||
|
|
||||||
class _AssertNumQueriesContext(CaptureQueriesContext):
|
class _AssertNumQueriesContext(CaptureQueriesContext):
|
||||||
def __init__(self, test_case, num, connection):
|
def __init__(self, test_case, num, connection):
|
||||||
|
@ -490,14 +482,10 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
conn.ops.sequence_reset_by_name_sql(no_style(),
|
conn.ops.sequence_reset_by_name_sql(no_style(),
|
||||||
conn.introspection.sequence_list())
|
conn.introspection.sequence_list())
|
||||||
if sql_list:
|
if sql_list:
|
||||||
try:
|
with transaction.commit_on_success_unless_managed(using=db_name):
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
for sql in sql_list:
|
for sql in sql_list:
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
except Exception:
|
|
||||||
transaction.rollback_unless_managed(using=db_name)
|
|
||||||
raise
|
|
||||||
transaction.commit_unless_managed(using=db_name)
|
|
||||||
|
|
||||||
def _fixture_setup(self):
|
def _fixture_setup(self):
|
||||||
for db_name in self._databases_names(include_mirrors=False):
|
for db_name in self._databases_names(include_mirrors=False):
|
||||||
|
@ -537,11 +525,6 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def _fixture_teardown(self):
|
def _fixture_teardown(self):
|
||||||
# Roll back any pending transactions in order to avoid a deadlock
|
|
||||||
# during flush when TEST_MIRROR is used (#18984).
|
|
||||||
for conn in connections.all():
|
|
||||||
conn.rollback_unless_managed()
|
|
||||||
|
|
||||||
for db in self._databases_names(include_mirrors=False):
|
for db in self._databases_names(include_mirrors=False):
|
||||||
call_command('flush', verbosity=0, interactive=False, database=db,
|
call_command('flush', verbosity=0, interactive=False, database=db,
|
||||||
skip_validation=True, reset_sequences=False)
|
skip_validation=True, reset_sequences=False)
|
||||||
|
|
|
@ -352,6 +352,8 @@ these changes.
|
||||||
- ``django.db.close_connection()``
|
- ``django.db.close_connection()``
|
||||||
- ``django.db.backends.creation.BaseDatabaseCreation.set_autocommit()``
|
- ``django.db.backends.creation.BaseDatabaseCreation.set_autocommit()``
|
||||||
- ``django.db.transaction.managed()``
|
- ``django.db.transaction.managed()``
|
||||||
|
- ``django.db.transaction.commit_unless_managed()``
|
||||||
|
- ``django.db.transaction.rollback_unless_managed()``
|
||||||
|
|
||||||
2.0
|
2.0
|
||||||
---
|
---
|
||||||
|
|
|
@ -208,38 +208,6 @@ class TestNewConnection(TransactionTestCase):
|
||||||
connection.leave_transaction_management()
|
connection.leave_transaction_management()
|
||||||
self.assertEqual(orig_dirty, connection._dirty)
|
self.assertEqual(orig_dirty, connection._dirty)
|
||||||
|
|
||||||
# TODO: update this test to account for database-level autocommit.
|
|
||||||
@expectedFailure
|
|
||||||
def test_commit_unless_managed(self):
|
|
||||||
cursor = connection.cursor()
|
|
||||||
cursor.execute("INSERT into transactions_regress_mod (fld) values (2)")
|
|
||||||
connection.commit_unless_managed()
|
|
||||||
self.assertFalse(connection.is_dirty())
|
|
||||||
self.assertEqual(len(Mod.objects.all()), 1)
|
|
||||||
self.assertTrue(connection.is_dirty())
|
|
||||||
connection.commit_unless_managed()
|
|
||||||
self.assertFalse(connection.is_dirty())
|
|
||||||
|
|
||||||
# TODO: update this test to account for database-level autocommit.
|
|
||||||
@expectedFailure
|
|
||||||
def test_commit_unless_managed_in_managed(self):
|
|
||||||
cursor = connection.cursor()
|
|
||||||
connection.enter_transaction_management()
|
|
||||||
cursor.execute("INSERT into transactions_regress_mod (fld) values (2)")
|
|
||||||
connection.commit_unless_managed()
|
|
||||||
self.assertTrue(connection.is_dirty())
|
|
||||||
connection.rollback()
|
|
||||||
self.assertFalse(connection.is_dirty())
|
|
||||||
self.assertEqual(len(Mod.objects.all()), 0)
|
|
||||||
connection.commit()
|
|
||||||
connection.leave_transaction_management()
|
|
||||||
self.assertFalse(connection.is_dirty())
|
|
||||||
self.assertEqual(len(Mod.objects.all()), 0)
|
|
||||||
self.assertTrue(connection.is_dirty())
|
|
||||||
connection.commit_unless_managed()
|
|
||||||
self.assertFalse(connection.is_dirty())
|
|
||||||
self.assertEqual(len(Mod.objects.all()), 0)
|
|
||||||
|
|
||||||
|
|
||||||
@skipUnless(connection.vendor == 'postgresql',
|
@skipUnless(connection.vendor == 'postgresql',
|
||||||
"This test only valid for PostgreSQL")
|
"This test only valid for PostgreSQL")
|
||||||
|
|
Loading…
Reference in New Issue