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

Jak*_*iak 1 python many-to-many sqlalchemy flask flask-sqlalchemy

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

错误(示例):

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

或者

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))
Run Code Online (Sandbox Code Playgroud)

关系表:

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'))
    )
Run Code Online (Sandbox Code Playgroud)

和型号:

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')
Run Code Online (Sandbox Code Playgroud)

最后是烧瓶代码:

@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')
Run Code Online (Sandbox Code Playgroud)

uni*_*rio 5

这是因为您已经为所需的每个关系设置了两个单独的关系。您有一个名为 的关系Book.authors和一个名为的反向引用Author.authors,以及一个名为 的关系Author.books和一个名为 的反向引用Book.books。这不起作用,因为它们都在 上操作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')
Run Code Online (Sandbox Code Playgroud)

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