Search code examples
foreign-keyshookpeeweecascading-deletes

Peewee How do i call post_delete signal for dependencies?


I see peewee has signal http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#signals

But it works only with delete_instance().

For what I hope are obvious reasons, Peewee signals do not work when you use the Model.insert(), Model.update(), or Model.delete() methods. These methods generate queries that execute beyond the scope of the ORM, and the ORM does not know about which model instances might or might not be affected when the query executes.

Signals work by hooking into the higher-level peewee APIs like Model.save() and Model.delete_instance(), where the affected model instance is known ahead of time.

So, how do i use signal on records which are dependencies since it use delete() on dependencies?

def delete_instance(self, recursive=False, delete_nullable=False):
        if recursive:
            dependencies = self.dependencies(delete_nullable)
            for query, fk in reversed(list(dependencies)):
                model = fk.model
                if fk.null and not delete_nullable:
                    model.update(**{fk.name: None}).where(query).execute()
                else:
                    model.delete().where(query).execute()
        return type(self).delete().where(self._pk_expr()).execute()

Solution

  • The short answer is that you can't, because recursive deletes are implemented using queries of the form:

    DELETE FROM ... WHERE foreign_key_id = X
    

    e.g., consider you have a user and they have created 1000 tweets. The tweet.user_id points to the user.id. When you delete that user, peewee issues 2 queries:

    DELETE FROM tweets WHERE user_id = 123
    DELETE FROM users WHERE id = 123
    

    If it were to call delete_instance() you would end up issuing 1001 queries instead. So it is hopefully quite clear why it is implemented in this way.

    I'd suggest that if you're deleting rows and need to perform some kind of cleanup on related rows, that you may be better off doing soft-deletes (e.g., setting a status=DELETED). Then do the processing of any relations outside of the signals API.