Used commit_on_success_unless_managed to make ORM operations atomic.
This commit is contained in:
parent
86fd920f67
commit
4dbd1b2dd8
|
@ -50,24 +50,6 @@ def DO_NOTHING(collector, field, sub_objs, using):
|
|||
pass
|
||||
|
||||
|
||||
def force_managed(func):
|
||||
@wraps(func)
|
||||
def decorated(self, *args, **kwargs):
|
||||
if transaction.get_autocommit(using=self.using):
|
||||
transaction.enter_transaction_management(using=self.using, forced=True)
|
||||
forced_managed = True
|
||||
else:
|
||||
forced_managed = False
|
||||
try:
|
||||
func(self, *args, **kwargs)
|
||||
if forced_managed:
|
||||
transaction.commit(using=self.using)
|
||||
finally:
|
||||
if forced_managed:
|
||||
transaction.leave_transaction_management(using=self.using)
|
||||
return decorated
|
||||
|
||||
|
||||
class Collector(object):
|
||||
def __init__(self, using):
|
||||
self.using = using
|
||||
|
@ -260,7 +242,6 @@ class Collector(object):
|
|||
self.data = SortedDict([(model, self.data[model])
|
||||
for model in sorted_models])
|
||||
|
||||
@force_managed
|
||||
def delete(self):
|
||||
# sort instance collections
|
||||
for model, instances in self.data.items():
|
||||
|
@ -271,40 +252,41 @@ class Collector(object):
|
|||
# end of a transaction.
|
||||
self.sort()
|
||||
|
||||
# send pre_delete signals
|
||||
for model, obj in self.instances_with_model():
|
||||
if not model._meta.auto_created:
|
||||
signals.pre_delete.send(
|
||||
sender=model, instance=obj, using=self.using
|
||||
)
|
||||
|
||||
# fast deletes
|
||||
for qs in self.fast_deletes:
|
||||
qs._raw_delete(using=self.using)
|
||||
|
||||
# update fields
|
||||
for model, instances_for_fieldvalues in six.iteritems(self.field_updates):
|
||||
query = sql.UpdateQuery(model)
|
||||
for (field, value), instances in six.iteritems(instances_for_fieldvalues):
|
||||
query.update_batch([obj.pk for obj in instances],
|
||||
{field.name: value}, self.using)
|
||||
|
||||
# reverse instance collections
|
||||
for instances in six.itervalues(self.data):
|
||||
instances.reverse()
|
||||
|
||||
# delete instances
|
||||
for model, instances in six.iteritems(self.data):
|
||||
query = sql.DeleteQuery(model)
|
||||
pk_list = [obj.pk for obj in instances]
|
||||
query.delete_batch(pk_list, self.using)
|
||||
|
||||
if not model._meta.auto_created:
|
||||
for obj in instances:
|
||||
signals.post_delete.send(
|
||||
with transaction.commit_on_success_unless_managed(using=self.using):
|
||||
# send pre_delete signals
|
||||
for model, obj in self.instances_with_model():
|
||||
if not model._meta.auto_created:
|
||||
signals.pre_delete.send(
|
||||
sender=model, instance=obj, using=self.using
|
||||
)
|
||||
|
||||
# fast deletes
|
||||
for qs in self.fast_deletes:
|
||||
qs._raw_delete(using=self.using)
|
||||
|
||||
# update fields
|
||||
for model, instances_for_fieldvalues in six.iteritems(self.field_updates):
|
||||
query = sql.UpdateQuery(model)
|
||||
for (field, value), instances in six.iteritems(instances_for_fieldvalues):
|
||||
query.update_batch([obj.pk for obj in instances],
|
||||
{field.name: value}, self.using)
|
||||
|
||||
# reverse instance collections
|
||||
for instances in six.itervalues(self.data):
|
||||
instances.reverse()
|
||||
|
||||
# delete instances
|
||||
for model, instances in six.iteritems(self.data):
|
||||
query = sql.DeleteQuery(model)
|
||||
pk_list = [obj.pk for obj in instances]
|
||||
query.delete_batch(pk_list, self.using)
|
||||
|
||||
if not model._meta.auto_created:
|
||||
for obj in instances:
|
||||
signals.post_delete.send(
|
||||
sender=model, instance=obj, using=self.using
|
||||
)
|
||||
|
||||
# update collected instances
|
||||
for model, instances_for_fieldvalues in six.iteritems(self.field_updates):
|
||||
for (field, value), instances in six.iteritems(instances_for_fieldvalues):
|
||||
|
|
|
@ -442,12 +442,7 @@ class QuerySet(object):
|
|||
self._for_write = True
|
||||
connection = connections[self.db]
|
||||
fields = self.model._meta.local_fields
|
||||
if transaction.get_autocommit(using=self.db):
|
||||
transaction.enter_transaction_management(using=self.db, forced=True)
|
||||
forced_managed = True
|
||||
else:
|
||||
forced_managed = False
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed(using=self.db):
|
||||
if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk
|
||||
and self.model._meta.has_auto_field):
|
||||
self._batched_insert(objs, fields, batch_size)
|
||||
|
@ -458,11 +453,6 @@ class QuerySet(object):
|
|||
if objs_without_pk:
|
||||
fields= [f for f in fields if not isinstance(f, AutoField)]
|
||||
self._batched_insert(objs_without_pk, fields, batch_size)
|
||||
if forced_managed:
|
||||
transaction.commit(using=self.db)
|
||||
finally:
|
||||
if forced_managed:
|
||||
transaction.leave_transaction_management(using=self.db)
|
||||
|
||||
return objs
|
||||
|
||||
|
@ -579,18 +569,8 @@ class QuerySet(object):
|
|||
self._for_write = True
|
||||
query = self.query.clone(sql.UpdateQuery)
|
||||
query.add_update_values(kwargs)
|
||||
if transaction.get_autocommit(using=self.db):
|
||||
transaction.enter_transaction_management(using=self.db, forced=True)
|
||||
forced_managed = True
|
||||
else:
|
||||
forced_managed = False
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed(using=self.db):
|
||||
rows = query.get_compiler(self.db).execute_sql(None)
|
||||
if forced_managed:
|
||||
transaction.commit(using=self.db)
|
||||
finally:
|
||||
if forced_managed:
|
||||
transaction.leave_transaction_management(using=self.db)
|
||||
self._result_cache = None
|
||||
return rows
|
||||
update.alters_data = True
|
||||
|
|
|
@ -16,11 +16,10 @@ Django's default behavior is to run in autocommit mode. Each query is
|
|||
immediately committed to the database. :ref:`See below for details
|
||||
<autocommit-details>`.
|
||||
|
||||
..
|
||||
Django uses transactions or savepoints automatically to guarantee the
|
||||
integrity of ORM operations that require multiple queries, especially
|
||||
:ref:`delete() <topics-db-queries-delete>` and :ref:`update()
|
||||
<topics-db-queries-update>` queries.
|
||||
Django uses transactions or savepoints automatically to guarantee the
|
||||
integrity of ORM operations that require multiple queries, especially
|
||||
:ref:`delete() <topics-db-queries-delete>` and :ref:`update()
|
||||
<topics-db-queries-update>` queries.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
Previous version of Django featured :ref:`a more complicated default
|
||||
|
|
Loading…
Reference in New Issue