我正在尝试从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()
答案 0 :(得分:4)
我认为错误消息是正确的:实际上在您的数据库中,您有2行链接Location
和Heading
个实例。在这种情况下,您应该首先找出这种情况发生的位置和原因,并防止再次发生
首先,要确认此假设,您可以针对您的数据库运行以下查询:
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
)
假设,通过手动删除数据库中的所有重复内容( )确认假设 fix 。
之后,在headings_locations
表中添加UniqueConstraint:
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
模型是不够的。
现在错误插入重复项的代码将因唯一约束违规异常而失败,您可以修复问题的根源。