Commit 4dbd1b2d authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Used commit_on_success_unless_managed to make ORM operations atomic.

parent 86fd920f
Loading
Loading
Loading
Loading
+32 −50
Original line number Diff line number Diff line
@@ -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,6 +252,7 @@ class Collector(object):
        # end of a transaction.
        self.sort()

        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:
+2 −22
Original line number Diff line number Diff line
@@ -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
+4 −5
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ 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()