postgresql - 从多对多 SQLAlchemy 和 Postgresql 中删除

标签 postgresql python-2.7 flask sqlalchemy flask-sqlalchemy

我正在尝试从 sql-alchemy 中的多对多关系中删除一个子对象。

我不断收到以下错误:

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

我查看了一些现有的 stackexchange 问题 ( SQLAlchemy DELETE Error caused by having a both lazy-load AND a dynamic version of the same relationship , SQLAlchemy StaleDataError on deleting items inserted via ORM sqlalchemy.orm.exc.StaleDataError , SQLAlchemy Attempting to Twice Delete Many to Many Secondary Relationship , Delete from Many to Many Relationship in MySQL ) 关于这一点以及阅读文档,但无法弄清楚为什么它不起作用。

我定义关系的代码如下:

headings_locations = db.Table('headings_locations',
        db.Column('id', db.Integer, primary_key=True),
        db.Column('location_id', db.Integer(), db.ForeignKey('location.id')),
        db.Column('headings_id', db.Integer(), db.ForeignKey('headings.id')))


class Headings(db.Model):
    __tablename__ = "headings"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    version = db.Column(db.Integer, default=1)
    special = db.Column(db.Boolean(), default=False)
    content = db.relationship('Content', backref=db.backref('heading'), cascade="all, delete-orphan") 
    created_date = db.Column(db.Date, default=datetime.datetime.utcnow())
    modified_date = db.Column(db.Date, default=datetime.datetime.utcnow(), onupdate=datetime.datetime.utcnow())

    def __init__(self, name):
        self.name = name



class Location(db.Model):

    __tablename__ = "location"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    account_id = db.Column(db.Integer, db.ForeignKey('account.id')) 
    version = db.Column(db.Integer, default=1)
    created_date = db.Column(db.Date, default=datetime.datetime.utcnow())
    modified_date = db.Column(db.Date, default=datetime.datetime.utcnow())
    location_prefix = db.Column(db.Integer)
    numbers = db.relationship('Numbers', backref=db.backref('location'), cascade="all, delete-orphan") 
    headings = db.relationship('Headings', secondary=headings_locations, 
                            backref=db.backref('locations', lazy='dynamic', cascade="all"))


    def __init__(self, name):
        self.name = name

而我的删除代码如下:

@content_blueprint.route('/delete_content/<int:location_id>/<int:heading_id>')
@login_required
def delete_content(location_id, heading_id):
    import pdb
    pdb.set_trace()
    location = db.session.query(Location).filter_by(id = location_id).first()
    heading = db.session.query(Headings).filter_by(id = heading_id).first()
    location.headings.remove(heading)
    #db.session.delete(heading)
    db.session.commit()
    flash('Data Updated, thank-you')
    return redirect(url_for('content.add_heading', location_id=location_id))

无论我尝试删除子对象(db.session.delete(heading) 或 location.headings.remove(heading))的哪种方式,我仍然会遇到同样的错误。

非常感谢任何帮助。

我的数据库是postgresql。

编辑: 我添加关系的代码:

        new_heading = Headings(form.new_heading.data)
        db.session.add(new_heading)
        location.headings.append(new_heading)
        db.session.commit()

最佳答案

我假设错误消息是正确的:确实在您的数据库中有 2 行链接 LocationHeading 实例。在这种情况下,您应该首先找出发生这种情况的位置和原因,并防止这种情况再次发生

  1. 首先,为了确认这个假设,您可以对您的数据库运行以下查询:

    q = session.query(
        headings_locations.c.location_id,
        headings_locations.c.heading_id,
        sa.func.count().label("# connections"),
    ).group_by(
        headings_locations.c.location_id,
        headings_locations.c.heading_id,
    ).having(
        sa.func.count() > 1
    )
    
  2. 假设假设得到证实,通过手动删除数据库中的所有重复项(每个只保留一个)来修复它。

  3. 之后,添加一个UniqueConstraint到您的 headings_locations 表:

    headings_locations = db.Table('headings_locations',
            db.Column('id', db.Integer, primary_key=True),
            db.Column('location_id', db.Integer(), db.ForeignKey('location.id')),
            db.Column('headings_id', db.Integer(), db.ForeignKey('headings.id')),
            db.UniqueConstraint('location_id', 'headings_id', name='UC_location_id_headings_id'),
    )
    

注意需要添加到数据库中,添加到sqlalchemy模型中是不够的。

现在,错误插入重复项的代码将因违反唯一约束异常而失败,您可以解决问题的根源。

关于postgresql - 从多对多 SQLAlchemy 和 Postgresql 中删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31768652/

相关文章:

python - 为什么在 Python 2.x 中使用 msvcrt 时会出现 IOError?

python - 遍历Python列表并将数字输出到列表

python - 扭曲的 Int16StringReceiver 小端字节顺序

python - 为什么要同时使用 Tornado 和 Flask?

python-3.x - 动态数据库连接 Flask-SQLAlchemy

mysql - 根据时间更新不同的行?

sql - Postgresql - 查询问题

sql - 使用键作为列将主表数据与另一个表中的键值属性连接起来

java - 在 Lambda 函数中获取返回值

python - 使用 '?' 作为 Flask 和 SQLite3 的占位符会产生 OperationalError。