diff options
| author | Loic Bistuer <loic.bistuer@sixmedia.com> | 2013-11-22 00:14:16 +0700 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2013-11-27 19:45:22 +0200 |
| commit | f450bc9f44bc1270eae911daa157c155c29d1d9d (patch) | |
| tree | 7d456e19e1e928d6616d7d0fe975feba87231be2 /django | |
| parent | 52015b963d263642957aec880b52ad4063b484cd (diff) | |
Added a bulk option to RelatedManager remove() and clear() methods
Refs #21169
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/contenttypes/generic.py | 27 | ||||
| -rw-r--r-- | django/db/models/fields/related.py | 29 | ||||
| -rw-r--r-- | django/db/models/query.py | 2 |
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() |
