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:
committed by
Anssi Kääriäinen
parent
52015b963d
commit
f450bc9f44
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user