Flask SQLAlchemy多对多StaleDataError

时间:2017-04-05 22:26:10

标签: python flask sqlalchemy flask-sqlalchemy

我正在使用Flask-SQLAlchemy。我有两个通过关联表共享关系的类。当我尝试删除其中一个表中的行时。我看到以下错误:

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

以下是我的模特:

tags = db.Table('tags',
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
    db.Column('post_id', db.Integer, db.ForeignKey('posts.id'))
)

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255))
    tags = db.relationship('Tag', secondary=tags,
                       backref=db.backref('posts', lazy='dynamic'))

    def __init__(self, **kwargs):
        super(Post, self).__init__(**kwargs)

    def __repr__(self):
        return '<title %r>' % self.title


class Tag(db.Model):
    __tablename__ = 'tag'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(120), unique=True)

这是我要删除的代码:

def remove_tag(tag_id):
    tag = Tag.query.get(tag_id)
    for post in tag.posts:
        p = Post.query.get(post.id)
        p.tags.remove(tag)
db.session.delete(tag)
db.session.commit()

我在这个应用程序之外的独立测试,数据库和环境中尝试了此代码的条带化版本。并且,它按预期工作,删除标记和关联的表行。

如果可能,我想知道:

  • 我是如何处理StaleDataError的?
  • 当我对.all()的查询没有显示多个用途时,为什么它匹配多行?
  • 如何防止这种情况发生?

提前感谢您的任何帮助。

最佳, 爱德华

2 个答案:

答案 0 :(得分:0)

有一个顿悟!

  

我是如何处理StaleDataError的情况的?

在测试我的编辑帖子页面时,我对数据库做了很多相同帖子的POST。

  

当我对.all()的查询没有多次使用时,为什么它匹配多行?

我的测试在关联表中创建了多个条目。换句话说,我多次playerBody.angularDamping = 1; 次。

  

如何防止这种情况发生?

将唯一约束添加到关联表以停止对数据库的多个条目。我还在视图中添加了检查以停止多个条目。

playerBody.angularDamping = 0;

迁移您的数据库。

如果您使用SQlite和Alembic,您很可能会遇到此错误:“不支持SQLite方言中的ALTER约束”。有关此问题的更多信息,请访问here

简而言之,如果这是一个开发数据库,​​则删除数据库会更容易。如果您在生产环境中,也许您应该考虑数据迁移并切换到另一个引擎。

答案 1 :(得分:0)

如果我无法修改标签并发布数据库模型(当我使用数据库迁移的开源项目时可能会导致很多问题),该怎么办?

我通过清除与tags相关的post_id来解决此问题,然后重置post.tags = [],最后删除帖子  项目

1.
sql = text('delete from tags where post_id = %s' % post_id)
db.engine.execute(sql)

2.
post.tags = []
db.session.merge(post)
db.session.commit()

3.
db.session.delete(post)
db.session.commit()