About Ensuring That No Objects Get Deleted by Accident

If you blindly set on_delete=models.CASCADE for foreign keys and then programmatically delete the parent object at some point, all children will be deleted too whether that's wanted or not.

You can check the related objects to be deleted before deletion using this utility function:

def get_cascade_deletion_objects(instance):
    """
    Returns all objects that would be deleted if this instance was deleted.
    """
    from django.db.models.deletion import Collector
    from django.db import router

    using = router.db_for_write(instance.__class__, instance=instance)
    collector = Collector(using=using)
    collector.collect([instance])

    # Get all objects grouped by model
    objects_to_be_deleted = collector.data

    # Count objects by model
    deletion_summary = {}
    for model, instances in objects_to_be_deleted.items():
        model_name = f"{model._meta.app_label}.{model._meta.model_name}"
        deletion_summary[model_name] = len(instances)

    return {
        "detailed": objects_to_be_deleted,  # Full object list grouped by model
        "summary": deletion_summary,  # Count by model type
        "total_count": sum(deletion_summary.values()),  # Total count of objects
    }

Then it would work like this:

>>> category = Category.objects.get(slug="dummy")
>>> info = get_cascade_deletion_objects(category)
>>> info
{
    "detailed": defaultdict(<class 'set'>, {
        <class 'categories.models.Category'>: { <Category: Dummy> },
        <class 'posts.models.Post'>: { <Post: Hello World>, <Post: Bye Bye> },
    }),
    "summary": {"categories.category": 1, "posts.post": 2},
    "total_count": 3,
}

By inspecting the objects to be deleted together, you can take an explicit action like attaching another category or skipping the deletion of the parent object.

Tips and Tricks Programming Development Django 5.2 Django 4.2 Django 3.2