Skip to content
Back to top
View this page
Edit this page

# 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`.