Is there a way to "lock" an object so that it can't be deleted without unlocking it? Kind of like the option often present on digital cameras.

If not, any other way of preventing the user from deleting an object?

Also, this is for an addon, so no problem with script-based answers as a last resort.


You can override the delete function to achieve this :

  • add protected boolean property for the object type
  • set this property to true to prevent the object from deletion
  • the new delete function will only delete unprotected objects

this is the new delete operator no other changes are needed just include it in your addon and it will override the default delete function :

import bpy
from bpy.props import BoolProperty

bpy.types.Object.protected = BoolProperty(name = 'protected', default = False)
def main(context):
    for obj in context.selected_objects:
        if not obj.protected :
        else :
            print(obj.name +' is protected')

class delete_override(bpy.types.Operator):
    """delete unprotected objects"""
    bl_idname = "object.delete"
    bl_label = "Object Delete Operator"

    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        return {'FINISHED'}

def register():

def unregister():

if __name__ == "__main__":
  • $\begingroup$ However, after reading the code a few times, would you mind explaining how it works? I can't seem to find where and how you override the default deletion operator... $\endgroup$
    – Ludwik
    Apr 25 '15 at 11:07
  • 3
    $\begingroup$ they have the same Id name bl_idname = "object.delete" so when you register it the old definition gets overwritten by this one $\endgroup$
    – Chebhou
    Apr 25 '15 at 11:09
  • 2
    $\begingroup$ I know this is old question but - how to get the "OK?" prompt from the original delete operator? $\endgroup$
    – spacer
    May 19 '16 at 10:54
  • 1
    $\begingroup$ @spacer for those reading this in >2.8, you can use: def invoke(self, context, event): return context.window_manager.invoke_confirm(self, event) $\endgroup$
    – Dion Moult
    Sep 9 at 4:45

ok the script above is very interesting. this is not overriding the operator context but replacing it. I'm not 100% sure about interactions but for example you have anymore the register menu (F9) where you can set options like confirm and use global there > bpy.ops.object.delete(use_global=False, confirm=False) so I wrote an addon using the normal delete with an override and a new key ctrl+del (ctrl+suppr azerty)

import bpy
from bpy.props import BoolProperty

bl_info = {
    "name": "protected_delete_addon",
    "author": "1C0D",
    "version": (0, 0, 1),
    "blender": (2, 80, 0),
    "location": "property>object>visibility",
    "description": "protect from deleting with a key ctrl+del",
    "category": "Object",

bpy.types.Object.protected_delete = BoolProperty(
name = 'protected_delete', 
default =False,
description='to apply to several obj from active-> right clic on checkbox > copy to selected',

class Delete_Override(bpy.types.Operator):
    """delete unprotected objects"""
    bl_idname = "object.delete_mod"
    bl_label = "Object Delete dd Operator"
    bl_options = {'REGISTER', 'UNDO'} 

    def poll(cls, context):
        return context.mode=='OBJECT'

    def execute(self, context):

        override = bpy.context.copy()  
#we override the context with a comprehensive list taking into account the property
        override['selected_objects'] = [obj for obj in selected if not obj.protected_delete]    

        return {'FINISHED'}

# a select operator to find back in a scene what object are protected      
class Delete_Override_Property_Select_Toggle(bpy.types.Operator):
        bl_idname = "object.del_override_toggle"
        bl_label = "Object Delete Operator"
        bl_options = {'REGISTER', 'UNDO'} 
        bl_description= "to select all propected objects" 

        def execute(self, context):        

            for obj in bpy.context.scene.objects:
                if obj.protected_delete:  

            return {'FINISHED'}    

def draw_delete_override(self, context):
    layout = self.layout
#based on the code in visibility panel (checkbox with name after)
    layout.use_property_split = True  
    flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)

    obj = context.object
    col = flow.column()
    col.prop(obj, "protected_delete", text="protected_delete") ##property
    row.label(text='select all protected_delete') ##select by property
    row.operator("object.del_override_toggle", text="",icon='ARROW_LEFTRIGHT')

addon_keymaps = []
def register():

    wm = bpy.context.window_manager       
    km = wm.keyconfigs.addon.keymaps.new(name = 'Object Mode')
    kmi = km.keymap_items.new('object.delete_mod', 'DEL', 'PRESS',ctrl=True)
    addon_keymaps.append((km, kmi))

def unregister():

    for km, kmi in addon_keymaps:

if __name__ == "__main__":

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.