Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Used commit_on_success_unless_managed to make ORM operations atomic.

  • Loading branch information...
commit 4dbd1b2dd8d997f439b0116748994fd538ff893a 1 parent 86fd920
@aaugustin aaugustin authored
View
82 django/db/models/deletion.py
@@ -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 @@ def sort(self):
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 @@ def delete(self):
# 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):
View
24 django/db/models/query.py
@@ -442,12 +442,7 @@ def bulk_create(self, objs, batch_size=None):
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 @@ def bulk_create(self, objs, batch_size=None):
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 @@ def update(self, **kwargs):
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
View
9 docs/topics/db/transactions.txt
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.