Prevent actual deletion of inlined one-to-many object -- orphan the object

Hi Django Community,

I have a model.py like follows:

class Parent(models.Model):
    name = models.CharField()

class Child(models.Model):
    name = models.CharField()
    parent = models.ForeignKey(Parent, related_name='children')

Then admin.py is set up as follows

@admin.register(Child)
class ChildAdmin(admin.ModelAdmin):
    model = Child

    # Prevent the Child model from showing up in the sidebar
    def has_module_permission(self, request):
        return False

class ChildInlineAdmin(admin.TabularInline):
    model = Child
    show_change_link = True

@admin.register(Composition)
class CompositionAdmin(admin.ModelAdmin):
    inlines = [
        ChildInlineAdmin,
    ]

Everything works great, just as I expect.

What I want to accomplish is… when a user is in the admin form for Parent and checks the “Delete” checkbox of a Child row within the tabular inline, I want to only disassociate the child from its parent, not actually delete it.

I’ll have other processes by which the database gets cleaned up of orphaned Child instances. (Wow, bad choice of words, but I don’t know what other word to use.) Perhaps an “age out” policy, but that’s to be determined at a later point. For now, I literally want to prevent deletion in the database but continue to be able to use the admin interface in the way it is intended/designed.

Basically, the Child model is so complex and full of information (the sample above is just an illustration) that I cannot risk a user accidentally checking the “Delete” checkbox and having the information go poof. Sure, there are other ways to do this, like backups and whatnot, but it seems to me the most sure way to do this is to actually retain the data but have the Child be completely disassociated with its former Parent instance—which will then still look and act as if it’s been deleted.

You have your choices in the on_delete clause.

Depending upon exactly how you want to handle this, you probably want either DO_NOTHING or SET_NULL. Or, if you want to create a separate anchor point for them, you could use SET().