diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2013-03-11 15:11:34 +0100 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2013-03-11 15:11:34 +0100 |
| commit | 14cddf51c5f001bb426ce7f7a83fdc52c8d8aee9 (patch) | |
| tree | 7658f47dfaafe0dd09fe62fd5525e8f6e6a41ba7 /django/db/models | |
| parent | 9cec689e6a7e299b3416519ee075b2316ecc5a64 (diff) | |
| parent | e654180ce2a11ef4c525497d6c40dc542e16806c (diff) | |
Merged branch 'database-level-autocommit'.
Fixed #2227: `atomic` supports nesting.
Fixed #6623: `commit_manually` is deprecated and `atomic` doesn't suffer from this defect.
Fixed #8320: the problem wasn't identified, but the legacy transaction management is deprecated.
Fixed #10744: the problem wasn't identified, but the legacy transaction management is deprecated.
Fixed #10813: since autocommit is enabled, it isn't necessary to rollback after errors any more.
Fixed #13742: savepoints are now implemented for SQLite.
Fixed #13870: transaction management in long running processes isn't a problem any more, and it's documented.
Fixed #14970: while it digresses on transaction management, this ticket essentially asks for autocommit on PostgreSQL.
Fixed #15694: `atomic` supports nesting.
Fixed #17887: autocommit makes it impossible for a connection to stay "idle of transaction".
Diffstat (limited to 'django/db/models')
| -rw-r--r-- | django/db/models/base.py | 82 | ||||
| -rw-r--r-- | django/db/models/deletion.py | 78 | ||||
| -rw-r--r-- | django/db/models/query.py | 28 |
3 files changed, 72 insertions, 116 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py index 543cdfc165..ab0e42d461 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -609,48 +609,48 @@ class Model(six.with_metaclass(ModelBase)): if 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. - pk_val = self._get_pk_val(meta) - pk_set = pk_val is not None - record_exists = True - manager = cls._base_manager - if pk_set: - # Determine if we should do an update (pk already exists, forced update, - # no force_insert) - if ((force_update or update_fields) or (not force_insert and - manager.using(using).filter(pk=pk_val).exists())): - if force_update or non_pks: - values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks] - if values: - rows = manager.using(using).filter(pk=pk_val)._update(values) - if force_update and not rows: - raise DatabaseError("Forced update did not affect any rows.") - if update_fields and not rows: - 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 + with transaction.commit_on_success_unless_managed(using=using): + # First, try an UPDATE. If that doesn't update anything, do an INSERT. + pk_val = self._get_pk_val(meta) + pk_set = pk_val is not None + record_exists = True + manager = cls._base_manager + if pk_set: + # Determine if we should do an update (pk already exists, forced update, + # no force_insert) + if ((force_update or update_fields) or (not force_insert and + manager.using(using).filter(pk=pk_val).exists())): + if force_update or non_pks: + values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks] + if values: + rows = manager.using(using).filter(pk=pk_val)._update(values) + if force_update and not rows: + raise DatabaseError("Forced update did not affect any rows.") + if update_fields and not rows: + 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)] + 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 - 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) + 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) + if update_pk: + setattr(self, meta.pk.attname, result) # Store the database on which the object was saved 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 # FIXME: It would be nice if there was an "update many" version of update # for situations like this. - for i, j in enumerate(id_list): - ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i) - transaction.commit_unless_managed(using=using) + with transaction.commit_on_success_unless_managed(using=using): + for i, j in enumerate(id_list): + ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i) def method_get_order(ordered_obj, self): diff --git a/django/db/models/deletion.py b/django/db/models/deletion.py index 81f74923c2..a04f05c73b 100644 --- a/django/db/models/deletion.py +++ b/django/db/models/deletion.py @@ -50,26 +50,6 @@ def DO_NOTHING(collector, field, sub_objs, using): pass -def force_managed(func): - @wraps(func) - def decorated(self, *args, **kwargs): - if not transaction.is_managed(using=self.using): - transaction.enter_transaction_management(using=self.using) - forced_managed = True - else: - forced_managed = False - try: - func(self, *args, **kwargs) - if forced_managed: - transaction.commit(using=self.using) - else: - transaction.commit_unless_managed(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 @@ -262,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(): @@ -273,39 +252,40 @@ 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 - ) + 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) + # 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) + # 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() + # 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) + # 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 - ) + 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): diff --git a/django/db/models/query.py b/django/db/models/query.py index 30be30ca43..22c7cfba32 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -442,12 +442,7 @@ class QuerySet(object): self._for_write = True connection = connections[self.db] fields = self.model._meta.local_fields - if not transaction.is_managed(using=self.db): - transaction.enter_transaction_management(using=self.db) - 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,13 +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) - else: - transaction.commit_unless_managed(using=self.db) - finally: - if forced_managed: - transaction.leave_transaction_management(using=self.db) return objs @@ -581,20 +569,8 @@ class QuerySet(object): self._for_write = True query = self.query.clone(sql.UpdateQuery) query.add_update_values(kwargs) - if not transaction.is_managed(using=self.db): - transaction.enter_transaction_management(using=self.db) - 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) - else: - transaction.commit_unless_managed(using=self.db) - finally: - if forced_managed: - transaction.leave_transaction_management(using=self.db) self._result_cache = None return rows update.alters_data = True |
