summaryrefslogtreecommitdiff
path: root/django/db/models
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2013-03-11 15:11:34 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2013-03-11 15:11:34 +0100
commit14cddf51c5f001bb426ce7f7a83fdc52c8d8aee9 (patch)
tree7658f47dfaafe0dd09fe62fd5525e8f6e6a41ba7 /django/db/models
parent9cec689e6a7e299b3416519ee075b2316ecc5a64 (diff)
parente654180ce2a11ef4c525497d6c40dc542e16806c (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.py82
-rw-r--r--django/db/models/deletion.py78
-rw-r--r--django/db/models/query.py28
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