删除多对多:Flask-Sqlalchemy尝试删除具有特定ID的每一行

时间:2017-08-29 13:51:57

标签: python flask sqlalchemy many-to-many flask-sqlalchemy

我一直在使用flask和flask-sqlalchemy从MySQL数据库中删除多对多记录。 似乎sqlalchemy试图删除关系表中的所有行,其中a的id与链接到b的相同。

错误(示例):

sqlalchemy.orm.exc.StaleDataError: DELETE statement on table 'ksiazka_autor' expected to delete 1 row(s); Only 0 were matched.

sqlalchemy.orm.exc.StaleDataError: DELETE statement on table 'ksiazka_wydawnictwo' expected to delete 552 row(s); Only 551 were matched.

INFO sqlalchemy.engine.base.Engine DELETE FROM ksiazka_kategoria WHERE ksiazka_kategoria.ksiazka_id = %s AND ksiazka_kategoria.kategoria_id = %s
2017-08-29 15:44:34,965 INFO sqlalchemy.engine.base.Engine ((166, 40), (167, 40), (168, 40), (169, 40), (170, 40), (171, 40), (172, 40), (173, 40)  ... displaying 10 of 178 total bound parameter sets ...  (1463, 19), (2046, 19))

关系表:

ksiazka_autor = db.Table('ksiazka_autor',
        db.Column('autor_id', db.Integer, db.ForeignKey('autor.id')),
        db.Column('ksiazka_id', db.Integer, db.ForeignKey('ksiazka.id'))
    )
        ksiazka_wydawnictwo = db.Table('ksiazka_wydawnictwo',
        db.Column('wydawnictwo_id', db.Integer, db.ForeignKey('wydawnictwo.id')),
        db.Column('ksiazka_id', db.Integer, db.ForeignKey('ksiazka.id'))
    )
    ksiazka_ilustrator = db.Table('ksiazka_ilustrator',
        db.Column('ilustrator_id', db.Integer, db.ForeignKey('ilustrator.id')),
        db.Column('ksiazka_id', db.Integer, db.ForeignKey('ksiazka.id'))
    )
    ksiazka_kategoria = db.Table('ksiazka_kategoria',
        db.Column('ksiazka_id', db.Integer, db.ForeignKey('ksiazka.id')),
        db.Column('kategoria_id', db.Integer, db.ForeignKey('kategoria.id'))
    )

模特:

class Book(db.Model):
    __tablename__ = 'ksiazka'
    id = db.Column('id', db.Integer, primary_key=True)
    [...]

    authors = db.relationship('Author', secondary=ksiazka_autor, backref='authors', cascade="all", lazy='dynamic')
    category = db.relationship('Category', secondary=ksiazka_kategoria, backref='category', cascade="all", lazy='dynamic')
    publisher = db.relationship('Publisher', secondary=ksiazka_wydawnictwo, backref='publisher', cascade="all", lazy='dynamic')
    artist = db.relationship('Artist', secondary=ksiazka_ilustrator, backref='artist', cascade="all", lazy='dynamic')

class Author(db.Model):
    __tablename__ = 'autor'
    id = db.Column('id', db.Integer, primary_key=True)
    [...]
    books = db.relationship('Book', secondary=ksiazka_autor, backref=db.backref('books'), lazy='joined')

class Category(db.Model):
    __tablename__ = 'kategoria'
    id = db.Column('id', db.Integer, primary_key=True)
    [...]
    cat_books = db.relationship('Book', secondary=ksiazka_kategoria, backref=db.backref('cat_books'), lazy='joined')

class Publisher(db.Model):
    __tablename__ = 'wydawnictwo'
    id = db.Column('id', db.Integer, primary_key=True)
    [...]
    pub_books = db.relationship('Book', secondary=ksiazka_wydawnictwo, backref=db.backref('pub_books'), lazy='joined')

class Artist(db.Model):
    __tablename__ = 'ilustrator'
    id = db.Column('id', db.Integer, primary_key=True)
    [...]
    art_books = db.relationship('Book', secondary=ksiazka_ilustrator, backref=db.backref('art_books'), lazy='joined')

最后是烧瓶代码:

@app.route('/delete/book/<id>')
def delete_book(id):
    book = Book.query.filter_by(id=id).first()
    db.session.delete(book)
    db.session.commit()
    return redirect('/home')

1 个答案:

答案 0 :(得分:2)

这是因为您为每个想要的关系设置了两个单独的关系。您有一个名为Book.authors的关系和一个名为Author.authors的backref,以及一个名为Author.books的关系和一个名为Book.books的backref。这不起作用,因为它们都在ksiazka_autor上运行,导致您看到的冲突。你的所有其他关系都是如此。

您想要的是使用back_populates选项:

class Book(db.Model):
    ...

    authors = db.relationship('Author', secondary=ksiazka_autor, back_populates='books', cascade="all", lazy='dynamic')

class Author(db.Model):
    ...
    books = db.relationship('Book', secondary=ksiazka_autor, back_populates='authors', lazy='joined')

手动删除相关实例并提交两次不是正确的解决方案。