Deletion¶
Added in version 4.5.0.
There is nothing special about deleting polymorphic models. The same rules apply as to the deletion of normal Django models that have parent/child relationships up and down a model inheritance hierarchy. Django must walk the model inheritance and relationship graph and collect all of the affected objects so that it can correctly order deletion SQL statements to respect database constraints and issue signals.
The polymorphic deletion logic is the same as the normal Django deletion logic because Django
already walks the model inheritance hierarchy. PolymorphicQuerySet and
PolymorphicManager disrupt this process by confusing Django’s graph
walker by returning concrete subclass instances instead of base class instances when it attempts to
walk reverse relationships to polymorphic models. To prevent this confusion,
django-polymorphic wraps the on_delete handlers of
reverse relations to polymorphic models with PolymorphicGuard
which disables polymorphic behavior on the related querysets during collection.
You may define your polymorphic models as you normally would using the standard Django
on_delete actions.
PolymorphicModel will automatically wrap the actions for you. actions
wrapped with PolymorphicGuard serialize in migrations as the
underlying wrapped action. This ensures migrations generated by versions of
django-polymorphic after 4.5.0 should be the same as with prior versions. The guard is also
unnecessary during migrations because Django generates basic managers instead of using the default
polymorphic managers.
It is a design goal of django-polymorphic that deletion should just work without any special
treatment. However if you encounter attribute errors or database integrity errors during deletion
you may manually wrap the on_delete action of reverse relations
to polymorphic models with PolymorphicGuard to disable polymorphic
behavior during deletion collection. If you encounter an issue like this
please report it to us. For example:
from polymorphic.models import PolymorphicModel
from polymorphic.deletion import PolymorphicGuard
from django.db import models
class MyModel(models.Model):
# ...
class RelatedModel(PolymorphicModel):
my_model = models.ForeignKey(
MyModel,
on_delete=PolymorphicGuard(models.CASCADE),
)
Deleting Children (upcasting)¶
When deleting a polymorphic model instance, you can choose to keep the parent model instances by
passing the keep_parents=True argument to the
delete() method. This will delete only the subclass
instance, and leave the parent instances intact. django-polymorphic will ensure that the
polymorphic_ctype fields of the parent instances are updated accordingly to reflect their new
concrete model type.
Tip
You can delete multiple levels of child rows by deleting the model from the desired parent
level. For example, if you have a model inheritance hierarchy of Base -> ChildA -> ChildB,
and you delete a ChildB row from its parent model ChildA instance both the ChildA
and ChildB rows will be deleted leaving a concrete row type of Base.