Postagem bem antiga, mas acabei de gastar uma ou duas horas nisso, então gostaria de compartilhar minha descoberta, especialmente porque alguns dos outros comentários listados não estão certos.
TL; DR
Dê à tabela filho um estrangeiro ou modifique o existente, adicionando ondelete='CASCADE':
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
E um dos seguintes relacionamentos:
a) Isso na tabela pai:
children = db.relationship('Child', backref='parent', passive_deletes=True)
b) Ou isso na mesa infantil:
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Detalhes
Em primeiro lugar, apesar do que diz a resposta aceita, a relação pai / filho não se estabelece usando relationship, é estabelecida usando ForeignKey. Você pode colocar o relationshipnas tabelas pai ou filho e funcionará bem. Embora, aparentemente nas tabelas filho, você tenha que usar a backreffunção além do argumento de palavra-chave.
Opção 1 (preferencial)
Em segundo lugar, SqlAlchemy oferece suporte a dois tipos diferentes de cascata. O primeiro, e o que eu recomendo, está embutido em seu banco de dados e geralmente assume a forma de uma restrição na declaração de chave estrangeira. No PostgreSQL, é assim:
CONSTRAINT child_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES parent_table(id) MATCH SIMPLE
ON DELETE CASCADE
Isso significa que quando você exclui um registro de parent_table, todas as linhas correspondentes em child_tableserão excluídas para você pelo banco de dados. É rápido e confiável e provavelmente sua melhor aposta. Você configura isso no SqlAlchemy ForeignKeyassim (parte da definição da tabela filho):
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
A ondelete='CASCADE'é a parte que cria o ON DELETE CASCADEsobre a mesa.
Peguei vocês!
Há uma advertência importante aqui. Observe como eu tenho um relationshipespecificado com passive_deletes=True? Se você não tiver isso, a coisa toda não funcionará. Isso ocorre porque, por padrão, quando você exclui um registro pai, o SqlAlchemy faz algo realmente estranho. Ele define as chaves estrangeiras de todas as linhas filhas como NULL. Portanto, se você excluir uma linha de parent_tableonde id= 5, ela basicamente executará
UPDATE child_table SET parent_id = NULL WHERE parent_id = 5
Por que você iria querer isso, eu não tenho ideia. Eu ficaria surpreso se muitos mecanismos de banco de dados permitissem que você definisse uma chave estrangeira válida para NULL, criando um órfão. Parece uma má ideia, mas talvez haja um caso de uso. De qualquer forma, se você deixar o SqlAlchemy fazer isso, você impedirá que o banco de dados seja capaz de limpar os filhos usando o ON DELETE CASCADEque você configurou. Isso ocorre porque ele depende dessas chaves estrangeiras para saber quais linhas filho excluir. Depois que o SqlAlchemy definir todos como NULL, o banco de dados não poderá excluí-los. A configuração passive_deletes=Trueevita que o SqlAlchemy NULLsaia das chaves estrangeiras.
Você pode ler mais sobre exclusões passivas nos documentos do SqlAlchemy .
opção 2
A outra maneira de fazer isso é deixar o SqlAlchemy fazer isso por você. Isso é configurado usando o cascadeargumento do relationship. Se você tiver o relacionamento definido na tabela pai, será assim:
children = relationship('Child', cascade='all,delete', backref='parent')
Se o relacionamento é por conta da criança, você faz assim:
parent = relationship('Parent', backref=backref('children', cascade='all,delete'))
Novamente, este é o filho, então você deve chamar um método chamado backrefe colocar os dados em cascata nele.
Com isso no lugar, quando você exclui uma linha pai, SqlAlchemy irá realmente executar instruções delete para você limpar as linhas filho. Provavelmente, isso não será tão eficiente quanto deixar esse banco de dados manipular se for para você, então eu não o recomendo.
Aqui estão os documentos do SqlAlchemy sobre os recursos em cascata suportados.