delete()

Deletes an existing ECM object. By default the object is moved to the recycle bin — with hard_delete=True it is permanently removed.

The object to delete can be identified either by a model instance or directly by object_id and object_type.

1. Signature

  • Sync

  • Async

ecm.dms.delete(
    model: ECMFolderModel | ECMRegisterModel | ECMDocumentModel | int,
    object_type: int | str | None = None,
    *,
    hard_delete: bool = False,
    delete_cascading: bool = False,
) -> None
await ecm.dms.delete(
    model: ECMFolderModel | ECMRegisterModel | ECMDocumentModel | int,
    object_type: int | str | None = None,
    *,
    hard_delete: bool = False,
    delete_cascading: bool = False,
) -> None

2. Parameters

Parameter Default Description

model

The object to delete — either a model instance with id set, or a plain int object ID (in which case object_type must be provided).

object_type

None

Only required when model is a plain int. Identifies the object type: int for a numeric type ID or str for the internal name.

hard_delete

False

When True, permanently deletes the object (HARDDELETE=1) instead of moving it to the recycle bin.

delete_cascading

False

When True, recursively deletes all child objects as well (DELETECASCADING=1). Useful for folders or registers with nested content.

3. Exceptions

ValueError

model is a plain int but object_type was not provided.

ValueError

model is a model instance with id = None.

4. Examples

4.1. Delete after loading

The most common case: load the object first, then delete it.

  • Sync

  • Async

folder = ecm.dms.get(InvoiceFolder, 12345)
ecm.dms.delete(folder)
folder = await ecm.dms.get(InvoiceFolder, 12345)
await ecm.dms.delete(folder)

4.2. Delete by object_id and internal name

If the ID is known, the object does not need to be fully loaded. Pass the internal name of the object type as object_type:

  • Sync

  • Async

ecm.dms.delete(12345, "InvoiceFolder")
await ecm.dms.delete(12345, "InvoiceFolder")

4.3. Delete by object_id and numeric type ID

Alternatively, use the numeric type ID when the internal name is not known:

  • Sync

  • Async

# Determine the type ID e.g. via get_object_type_by_id()
type_id = ecm.dms.get_object_type_by_id(12345)
ecm.dms.delete(12345, type_id)
type_id = await ecm.dms.get_object_type_by_id(12345)
await ecm.dms.delete(12345, type_id)

4.4. Permanent delete (bypass recycle bin)

With hard_delete=True the object is removed permanently and cannot be restored:

  • Sync

  • Async

ecm.dms.delete(12345, "InvoiceFolder", hard_delete=True)
await ecm.dms.delete(12345, "InvoiceFolder", hard_delete=True)

4.5. Delete a folder with its entire subtree

With delete_cascading=True all child registers and documents are deleted as well:

  • Sync

  • Async

ecm.dms.delete(42, "InvoiceFolder", delete_cascading=True)
await ecm.dms.delete(42, "InvoiceFolder", delete_cascading=True)

4.6. Delete all results of a query

Delete objects in batches: each iteration fetches a limited number of objects and deletes them, repeating until no more results are returned. This avoids loading everything into memory at once and sidesteps the paging inconsistencies of stream() when objects are deleted while iterating.

  • Sync

  • Async

while True:
    batch = (
        ecm.dms.select(InvoiceFolder)
        .where(InvoiceFolder.Year == 2020)
        .limit(100)
        .execute()
    )
    if not batch:
        break
    for folder in batch:
        ecm.dms.delete(folder, hard_delete=True, delete_cascading=True)
while True:
    batch = await (
        ecm.dms.select(InvoiceFolder)
        .where(InvoiceFolder.Year == 2020)
        .limit(100)
        .execute()
    )
    if not batch:
        break
    for folder in batch:
        await ecm.dms.delete(folder, hard_delete=True, delete_cascading=True)

5. See also

  • get() — Load a single object by its ID

  • select() — Query objects with a typed model

  • insert() — Create a new object