2014-04-27 16 views
9

ho la seguente configurazione SQLAlchemy:SQLAlchemy: Cancellare oggetto direttamente da uno-a-molti senza utilizzare Session.delete()

Base = declarative_base() 

class Post(Base): 
    __tablename__ = 'post' 
    id = Column(Integer, primary_key=True) 
    title = Column(String(30)) 
    comments = relationship('Comment', cascade='all') 

class Comment(Base): 
    __tablename__ = 'comment' 
    id = Column(Integer, primary_key=True) 
    post_id = Column(Integer, ForeignKey(Post.id, ondelete='CASCADE'), nullable=False) 
    text = Column(Text) 

Con questo, posso creare oggetti postali con un one-to molte relazioni con i commenti. Voglio gestire la creazione e la cancellazione dei commenti per i post senza fare riferimento alla sessione. L'aggiunta di un commento ad un post funziona bene:

post = Post(title='some post') 
comment = Comment(text='some comment') 
post.comments.append(comment) 

mio gestore di sessione conosce solo i messaggi, quindi sarebbe fare un session.add(post) e il commento viene inserito nella sessione automaticamente e viene sincronizzato con il database sul prossimo session.commit() . Tuttavia, lo stesso non è vero per la cancellazione dei commenti. Voglio essere in grado di cancellare un commento da solo facendo:

post.comments.remove(comment) 

Tuttavia, questo produce il seguente errore sul prossimo session.commit():

sqlalchemy.exc.OperationalError: (OperationalError) (1048, "Column 'post_id' cannot be null") 'UPDATE comment SET post_id=%s WHERE comment.id = %s' (None, 1L) 

Come faccio a dire SQLAlchemy di non aggiornare il commento con un valore NULL per post_id (che non è consentito a causa del vincolo non nullo sulla colonna), ma eliminare invece il commento? So che potrei fare session.delete(comment), ma poiché non ho bisogno di aggiungere il commento alla sessione in modo esplicito, non vedo un motivo per cui dovrei doverlo eliminare esplicitamente dalla sessione.

Ho trovato diverse soluzioni per le eliminazioni in cascata di oggetti correlati, ma poiché non ho mai pubblicato alcuna cancellazione esplicita per la sessione (il post è ancora lì), non penso che sia applicabile.

Modifica: ho modificato l'esempio per includere la sovrapposizione di cancellazioni dai post. Ora funziona per fare session.delete(post) e tutti i commenti sono cancellati. Ma voglio solo cancellare automaticamente i commenti che ho rimosso dalla relazione e non eliminare l'intero post con tutti i commenti.

TL; DR: Come si comunica a SQLAlchemy di emettere un'istruzione di eliminazione anziché un'istruzione di aggiornamento quando rimuovo una voce da un elenco di relazioni di una relazione uno-a-molti?

risposta

5

Leggi Configuring delete/delete-orphan Cascade sezione della documentazione per ulteriori informazioni, ma fondamentalmente è necessario delete-orphan pure nella vostra opzione del relationshipcascade:

class Post(Base): 
    # ... 
    comments = relationship('Comment', cascade="all, delete-orphan") 
+0

Con l'opzione 'delete-orphan' nelle cascate, la cancellazione alla rimozione dall'elenco delle relazioni funziona come previsto. Grazie. – Varicus

0

io non sono un utente SQLAlchemy, ma penso che si dovrebbe utilizzare l'opzione onDelete

 
    post_id = Column(Integer, ForeignKey(Post.id, ondelete="CASCADE"), nullable=False) 

See, Mysql 5.6 Manuale vincoli 13.6.44, chiave esterna

 
SET NULL: Delete or update the row from the parent table, and set the foreign key column or columns in the child table to NULL. 
Both ON DELETE SET NULL and ON UPDATE SET NULL clauses are supported. 
 
CASCADE: Delete or update the row from the parent table, and automatically delete or update the matching rows in the child table. 
Both ON DELETE CASCADE and ON UPDATE CASCADE are supported. Between two tables, do not define several ON UPDATE 
CASCADE clauses that act on the same column in the parent table or in the child table. 

E http://docs.sqlalchemy.org/en/rel_0_9/core/constraints.html Sezione: Definire chiavi esterne -> ON UPDATE e ON DELETE

+0

che probabilmente funzionerà quando si elimina il post utilizzando 'Session.delete (post)', ma Non lo sto facendo. Quindi non c'è niente da fare a cascata per il commento. Voglio solo cancellare il commento. – Varicus