Loading django/db/models/base.py +2 −2 Original line number Diff line number Diff line Loading @@ -827,7 +827,7 @@ class Model(six.with_metaclass(ModelBase)): return manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) def delete(self, using=None): def delete(self, using=None, keep_parents=False): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its %s attribute is set to None." % Loading @@ -835,7 +835,7 @@ class Model(six.with_metaclass(ModelBase)): ) collector = Collector(using=using) collector.collect([self]) collector.collect([self], keep_parents=keep_parents) collector.delete() delete.alters_data = True Loading django/db/models/deletion.py +19 −15 Original line number Diff line number Diff line Loading @@ -174,7 +174,7 @@ class Collector(object): return [objs] def collect(self, objs, source=None, nullable=False, collect_related=True, source_attr=None, reverse_dependency=False): source_attr=None, reverse_dependency=False, keep_parents=False): """ Adds 'objs' to the collection of objects to be deleted as well as all parent instances. 'objs' must be a homogeneous iterable collection of Loading @@ -189,6 +189,9 @@ class Collector(object): current model, rather than after. (Needed for cascading to parent models, the one case in which the cascade follows the forwards direction of an FK rather than the reverse direction.) If 'keep_parents' is False, data of parent's models will be not deleted. """ if self.can_fast_delete(objs): self.fast_deletes.append(objs) Loading @@ -200,6 +203,7 @@ class Collector(object): model = new_objs[0].__class__ if not keep_parents: # Recursively collect concrete model's parent models, but not their # related objects. These will be found by meta.get_fields() concrete_model = model._meta.concrete_model Loading docs/ref/models/instances.txt +9 −1 Original line number Diff line number Diff line Loading @@ -533,7 +533,7 @@ value, the field will be added to the updated fields. Deleting objects ================ .. method:: Model.delete([using=DEFAULT_DB_ALIAS]) .. method:: Model.delete([using=DEFAULT_DB_ALIAS, keep_parents=False]) Issues an SQL ``DELETE`` for the object. This only deletes the object in the database; the Python instance will still exist and will still have data in Loading @@ -545,6 +545,14 @@ For more details, including how to delete objects in bulk, see If you want customized deletion behavior, you can override the ``delete()`` method. See :ref:`overriding-model-methods` for more details. Sometimes with :ref:`multi-table inheritance <multi-table-inheritance>` you may want to delete only a child model's data. Specifying ``keep_parents=True`` will keep the parent model's data. .. versionchanged:: 1.9 The ``keep_parents`` parameter was added. Pickling objects ================ Loading docs/releases/1.9.txt +4 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,10 @@ Models managers created by ``ForeignKey``, ``GenericForeignKey``, and ``ManyToManyField``. * Added the ``keep_parents`` parameter to :meth:`Model.delete() <django.db.models.Model.delete>` to allow deleting only a child's data in a model that uses multi-table inheritance. CSRF ^^^^ Loading tests/delete/tests.py +7 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,13 @@ class DeletionTests(TestCase): self.assertFalse(S.objects.exists()) self.assertFalse(T.objects.exists()) def test_delete_with_keeping_parents(self): child = RChild.objects.create() parent_id = child.r_ptr_id child.delete(keep_parents=True) self.assertFalse(RChild.objects.filter(id=child.id).exists()) self.assertTrue(R.objects.filter(id=parent_id).exists()) class FastDeleteTests(TestCase): Loading Loading
django/db/models/base.py +2 −2 Original line number Diff line number Diff line Loading @@ -827,7 +827,7 @@ class Model(six.with_metaclass(ModelBase)): return manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) def delete(self, using=None): def delete(self, using=None, keep_parents=False): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, ( "%s object can't be deleted because its %s attribute is set to None." % Loading @@ -835,7 +835,7 @@ class Model(six.with_metaclass(ModelBase)): ) collector = Collector(using=using) collector.collect([self]) collector.collect([self], keep_parents=keep_parents) collector.delete() delete.alters_data = True Loading
django/db/models/deletion.py +19 −15 Original line number Diff line number Diff line Loading @@ -174,7 +174,7 @@ class Collector(object): return [objs] def collect(self, objs, source=None, nullable=False, collect_related=True, source_attr=None, reverse_dependency=False): source_attr=None, reverse_dependency=False, keep_parents=False): """ Adds 'objs' to the collection of objects to be deleted as well as all parent instances. 'objs' must be a homogeneous iterable collection of Loading @@ -189,6 +189,9 @@ class Collector(object): current model, rather than after. (Needed for cascading to parent models, the one case in which the cascade follows the forwards direction of an FK rather than the reverse direction.) If 'keep_parents' is False, data of parent's models will be not deleted. """ if self.can_fast_delete(objs): self.fast_deletes.append(objs) Loading @@ -200,6 +203,7 @@ class Collector(object): model = new_objs[0].__class__ if not keep_parents: # Recursively collect concrete model's parent models, but not their # related objects. These will be found by meta.get_fields() concrete_model = model._meta.concrete_model Loading
docs/ref/models/instances.txt +9 −1 Original line number Diff line number Diff line Loading @@ -533,7 +533,7 @@ value, the field will be added to the updated fields. Deleting objects ================ .. method:: Model.delete([using=DEFAULT_DB_ALIAS]) .. method:: Model.delete([using=DEFAULT_DB_ALIAS, keep_parents=False]) Issues an SQL ``DELETE`` for the object. This only deletes the object in the database; the Python instance will still exist and will still have data in Loading @@ -545,6 +545,14 @@ For more details, including how to delete objects in bulk, see If you want customized deletion behavior, you can override the ``delete()`` method. See :ref:`overriding-model-methods` for more details. Sometimes with :ref:`multi-table inheritance <multi-table-inheritance>` you may want to delete only a child model's data. Specifying ``keep_parents=True`` will keep the parent model's data. .. versionchanged:: 1.9 The ``keep_parents`` parameter was added. Pickling objects ================ Loading
docs/releases/1.9.txt +4 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,10 @@ Models managers created by ``ForeignKey``, ``GenericForeignKey``, and ``ManyToManyField``. * Added the ``keep_parents`` parameter to :meth:`Model.delete() <django.db.models.Model.delete>` to allow deleting only a child's data in a model that uses multi-table inheritance. CSRF ^^^^ Loading
tests/delete/tests.py +7 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,13 @@ class DeletionTests(TestCase): self.assertFalse(S.objects.exists()) self.assertFalse(T.objects.exists()) def test_delete_with_keeping_parents(self): child = RChild.objects.create() parent_id = child.r_ptr_id child.delete(keep_parents=True) self.assertFalse(RChild.objects.filter(id=child.id).exists()) self.assertTrue(R.objects.filter(id=parent_id).exists()) class FastDeleteTests(TestCase): Loading