1
0
mirror of https://github.com/django/django.git synced 2025-10-24 22:26:08 +00:00

Added a bulk option to RelatedManager remove() and clear() methods

Refs #21169
This commit is contained in:
Loic Bistuer
2013-11-22 00:14:16 +07:00
committed by Anssi Kääriäinen
parent 52015b963d
commit f450bc9f44
6 changed files with 90 additions and 37 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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()