summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorLoic Bistuer <loic.bistuer@sixmedia.com>2013-11-22 00:14:16 +0700
committerAnssi Kääriäinen <akaariai@gmail.com>2013-11-27 19:45:22 +0200
commitf450bc9f44bc1270eae911daa157c155c29d1d9d (patch)
tree7d456e19e1e928d6616d7d0fe975feba87231be2 /django
parent52015b963d263642957aec880b52ad4063b484cd (diff)
Added a bulk option to RelatedManager remove() and clear() methods
Refs #21169
Diffstat (limited to 'django')
-rw-r--r--django/contrib/contenttypes/generic.py27
-rw-r--r--django/db/models/fields/related.py29
-rw-r--r--django/db/models/query.py2
3 files changed, 40 insertions, 18 deletions
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
index 469e64db33..9ef499bb16 100644
--- a/django/contrib/contenttypes/generic.py
+++ b/django/contrib/contenttypes/generic.py
@@ -8,7 +8,7 @@ from functools import partial
from django.core.exceptions import ObjectDoesNotExist
from django.db import connection
-from django.db import models, router, DEFAULT_DB_ALIAS
+from django.db import models, router, transaction, DEFAULT_DB_ALIAS
from django.db.models import signals
from django.db.models.fields.related import ForeignObject, ForeignObjectRel
from django.db.models.related import PathInfo
@@ -382,16 +382,29 @@ def create_generic_related_manager(superclass):
obj.save()
add.alters_data = True
- def remove(self, *objs):
- db = router.db_for_write(self.model, instance=self.instance)
- self.using(db).filter(pk__in=[o.pk for o in objs]).delete()
+ def remove(self, *objs, **kwargs):
+ if not objs:
+ return
+ bulk = kwargs.pop('bulk', True)
+ self._clear(self.filter(pk__in=[o.pk for o in objs]), bulk)
remove.alters_data = True
- def clear(self):
- db = router.db_for_write(self.model, instance=self.instance)
- self.using(db).delete()
+ def clear(self, **kwargs):
+ bulk = kwargs.pop('bulk', True)
+ self._clear(self, bulk)
clear.alters_data = True
+ def _clear(self, queryset, bulk):
+ db = router.db_for_write(self.model, instance=self.instance)
+ queryset = queryset.using(db)
+ if bulk:
+ queryset.delete()
+ else:
+ with transaction.commit_on_success_unless_managed(using=db, savepoint=False):
+ for obj in queryset:
+ obj.delete()
+ _clear.alters_data = True
+
def create(self, **kwargs):
kwargs[self.content_type_field_name] = self.content_type
kwargs[self.object_id_field_name] = self.pk_val
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 62c7248de2..4a945e0f45 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -463,13 +463,11 @@ def create_foreign_related_manager(superclass, rel_field, rel_model):
# remove() and clear() are only provided if the ForeignKey can have a value of null.
if rel_field.null:
- def remove(self, *objs):
- # If there aren't any objects, there is nothing to do.
+ def remove(self, *objs, **kwargs):
if not objs:
return
-
+ bulk = kwargs.pop('bulk', True)
val = rel_field.get_foreign_related_value(self.instance)
-
old_ids = set()
for obj in objs:
# Is obj actually part of this descriptor set?
@@ -477,14 +475,26 @@ def create_foreign_related_manager(superclass, rel_field, rel_model):
old_ids.add(obj.pk)
else:
raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, self.instance))
-
- self.filter(pk__in=old_ids).update(**{rel_field.name: None})
+ self._clear(self.filter(pk__in=old_ids), bulk)
remove.alters_data = True
- def clear(self):
- self.update(**{rel_field.name: None})
+ def clear(self, **kwargs):
+ bulk = kwargs.pop('bulk', True)
+ self._clear(self, bulk)
clear.alters_data = True
+ def _clear(self, queryset, bulk):
+ db = router.db_for_write(self.model, instance=self.instance)
+ queryset = queryset.using(db)
+ if bulk:
+ queryset.update(**{rel_field.name: None})
+ else:
+ with transaction.commit_on_success_unless_managed(using=db, savepoint=False):
+ for obj in queryset:
+ setattr(obj, rel_field.name, None)
+ obj.save()
+ _clear.alters_data = True
+
return RelatedManager
@@ -657,6 +667,7 @@ def create_many_related_manager(superclass, rel):
signals.m2m_changed.send(sender=self.through, action="pre_clear",
instance=self.instance, reverse=self.reverse,
model=self.model, pk_set=None, using=db)
+
filters = self._build_remove_filters(super(ManyRelatedManager, self).get_queryset().using(db))
self.through._default_manager.using(db).filter(filters).delete()
@@ -746,8 +757,6 @@ def create_many_related_manager(superclass, rel):
# source_field_name: the PK colname in join table for the source object
# target_field_name: the PK colname in join table for the target object
# *objs - objects to remove
-
- # If there aren't any objects, there is nothing to do.
if not objs:
return
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 59a2b45d02..1737626d16 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1030,7 +1030,7 @@ class QuerySet(object):
"""
Checks if this QuerySet has any filtering going on. Note that this
isn't equivalent for checking if all objects are present in results,
- for example qs[1:]._has_filters() -> True.
+ for example qs[1:]._has_filters() -> False.
"""
return self.query.has_filters()