从多对多 SQL-Alchemy 和 Postgresql 中删除

rob*_*123 7 postgresql sqlalchemy flask python-2.7 flask-sqlalchemy

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

我不断收到以下错误:

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

我查看了一些现有的堆栈交换问题(SQLAlchemy DELETE 错误由具有相同关系的延迟加载和动态版本引起SQLAlchemy StaleDataError 在删除通过 ORM 插入的项目时发生 sqlalchemy.orm.exc.StaleDataErrorSQLAlchemy Attempting两次删除多对多次要关系从 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
Run Code Online (Sandbox Code Playgroud)

我的删除代码如下:

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

无论我尝试以哪种方式删除子对象(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()
Run Code Online (Sandbox Code Playgroud)

van*_*van 7

我会假设错误消息是正确的:确实在您的数据库中,您有 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
    )
    
    Run Code Online (Sandbox Code Playgroud)
  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'),
    )
    
    Run Code Online (Sandbox Code Playgroud)

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

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


归档时间:

查看次数:

2876 次

最近记录:

10 年,1 月 前