mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Used commit_on_success_unless_managed to make ORM operations atomic.
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user