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.