Reputation: 2647
I am having problems deleting records from PostTag
table that contains Post
and Tag
column. This is my relation table:
tags = db.Table('PostTag',
db.Column('Tag', db.Integer, db.ForeignKey('Tag.Id')),
db.Column('Post', db.Integer, db.ForeignKey('Post.Id'))
)
and
tags = db.relationship(Tag, secondary=tags, backref=db.backref('Post', lazy='dynamic'))
When I do this:
from models.Post import Post
posts = Post.query.join(Post.tags).filter(Post.Id == id).all()
if(posts):
return posts
return False
and then
for posttag in post[0].tags:
db.session.delete(posttag)
db.session.flush()
Rows from many-to-many relation are deleted but also records from Tag
table.
I just need to delete records from PostTag
table for some condition (Post=1
for example)
I searched the internet but I did not find anything conclusive. I do not need cascade on many-to-many relationship.
This is sql log:
297 Query DELETE FROM `PostTag` WHERE `PostTag`.`Tag` = 14 AND `PostTag`.`Post` = 3
297 Query DELETE FROM `PostTag` WHERE `PostTag`.`Tag` = 14 AND `PostTag`.`Post` = 18
297 Query DELETE FROM `Tag` WHERE `Tag`.`Id` = 14
Last row 297 Query DELETE FROM
TagWHERE
Tag.
Id= 14
should not be there.
UPDATE / maybe solution
I kind of solved this with:
sql = 'DELETE FROM PostTag WHERE Post=%s'
db.engine.execute(sql, post, ())
But that is not just ORM way. Same goes for insert. I will try to get this resolved ORM way. I will post answer if I make this problem go away.
Upvotes: 32
Views: 39018
Reputation: 694
Try this:
post = db.session.query(Post).get(1)
post.tags = []
db.session.commit()
Here we are redefining the collection post.tags
to the empty array and committing the changes. To explain this I'll refer to the SQLAlchemy docs:
Collections in SQLAlchemy are transparently instrumented. Instrumentation means that normal operations on the collection are tracked and result in changes being written to the database at flush time.
So SQLAlchemy keeps track of the changes we make to the collection post.tags and updates it on commit.
If we had only one tag (say sometag
) we could use the remove
method like this:
post = db.session.query(Post).get(1)
post.tags.remove(sometag)
db.session.commit()
Upvotes: 40
Reputation: 12202
Try to remove objects from the collection instead:
post[0].tags.clear()
You could also remove individual items:
post[0].tags.remove(posttag)
Upvotes: 11