【问题标题】:Sqlalchemy event `append` listener causes UNIQUE constraint failedSqlalchemy 事件“追加”侦听器导致 UNIQUE 约束失败
【发布时间】:2017-09-14 19:26:06
【问题描述】:
 class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)

class Paper(db.Model):
    __tablename__ = 'papers'
    id = db.Column(db.Integer, primary_key=True)
    reviewers = db.relationship('User', secondary=paper_reviewer,
                                backref=db.backref('papers_reviewed',
                                                   lazy='dynamic'),
                                lazy='dynamic')

paper_reviewer = db.Table('paper_reviewer',
                          db.Column('user_id', db.Integer,
                                    db.ForeignKey('users.id'),
                                    primary_key=True),
                          db.Column('paper_id', db.Integer,
                                    db.ForeignKey('papers.id'),
                                    primary_key=True)
                          )

@event.listens_for(Paper.reviewers, 'append')
def paper_reviewers_append(target, value, initiator):
    # db operation on other tables
    # target is paper obj
    print target.reviewers.all() # or other operation


paper.reviewers.append(usr)
db.session.add(paper)
db.session.commit()

侦听器在paper.reviewers.append(usr) 执行之前被触发。 append 的执行对 paper_reviewer 表进行了两次插入。第二个原因是IntegrityError: UNIQUE constraint failed

我在监听器中尝试了不同的操作。如果该操作触发了任何查询,则会在执行 commit() 时引发 IntegrityError。

【问题讨论】:

  • 您必须提供 [mvce]。 # db operation on other tables 不足以说明问题。
  • @univerio 我在描述中已经提到:如果操作触发了任何查询,则会在执行 commit() 时引发 IntegrityError。调用哪个表无关紧要。
  • 我知道你已经描述了你在做什么。我要的是一个可以运行的具体示例。如果是任何查询,则输入您想要的任何查询。想想我需要采取哪些步骤来重现您的问题;我需要添加缺少的User 模型,然后解释db operation on other tables 的意思,最后,如果一切正常,再猜猜我是否正确解释了db operation on other tables。提供一个完整的例子将消除其他变量。抱歉,我之前弄乱了链接:minimal reproducible example
  • @univerio 谢谢回复。我没想到你会尝试运行代码。类似的问题已经发布在 google group 上。解决方案是“您的侦听器中可能发生了自动刷新,因此请使用“with session.no_autoflush”:docs.sqlalchemy.org/en/latest/orm/…
  • 通用的“禁用自动刷新”似乎是个坏建议。了解 autoflush 实际上是什么以及它发生的原因(查询可能会观察到陈旧状态,如果会话有修改),与实际正在执行的操作相关,这将有更多帮助,此处仍未显示。

标签: python flask sqlalchemy flask-sqlalchemy


【解决方案1】:

我引用了一个 google 小组成员的解决方案 “您的听众中可能发生了自动刷新,因此请使用“与 session.no_autoflush": http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=autocommit#sqlalchemy.orm.session.Session.no_autoflush"

@event.listens_for(Paper.reviewers, 'append')
def paper_reviewers_append(target, value, initiator):
"""Update review preference."""
with db.session.no_autoflush:
    # db operation on other tables
    pass

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 2018-11-17
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    • 2020-04-24
    • 1970-01-01
    相关资源
    最近更新 更多