为什么我收到sqlalchemy.exc.IntegrityError

时间:2018-10-08 07:41:15

标签: python sqlalchemy flask-sqlalchemy

我面对错误,我无法理解的女巫感:

我写模型:

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))

class UserFile(db.Model):
    __tablename__ = 'user_files'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    author = db.relationship(User, foreign_keys=[author_id])

删除UserFile实例时,我需要执行许多其他步骤。

直接删除UserFile实例后,我可以做任何我想做的事。删除用户实例时出现问题。在这种情况下,我需要删除与该用户关联的所有UserFile实例。但是我不能使用级联删除,因为我需要为每个UserFile执行其他操作。

我尝试使用SQLAlchemy'before_delete'事件,但是我收到一个错误,因为它在删除后已经在运行,尽管它被称为'before'。我是通过将消息的输出添加到控制台来看到此消息的,直到收到错误后才在控制台中看到此消息。

然后我尝试使用FLASK-sqlalchemy信号。我做到了:

从flask_sqlalchemy导入before_models_committed

@before_models_committed.connect_via(app)
def delete_all_user_folders_after_delete(sender, changes):
    for obj, operation in changes:
        if isinstance(obj, User) and operation == 'delete':
            print('files: ', UserFile.query.filter_by(author_id=obj.id, parent_id=None).all())
            for item in UserFile.query.filter_by(author_id=obj.id,
                                                 parent_id=None).all():
                print(item)
                delete_file(item, True)

并在网上出现错误:

print ('files: ', UserFile.query.filter_by(author_id=obj.id, parent_id=None).all())

此错误的原因是什么?如何在删除用户之前正确预删除所有用户文件?

错误说明:

sqlalchemy.exc.IntegrityError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (psycopg2.IntegrityError) update or delete on table "users" violates foreign key constraint "user_files_author_id_fkey" on table "user_files"
DETAIL:  Key (id)=(2) is still referenced from table "user_files".

1 个答案:

答案 0 :(得分:0)

delete_all_user_folders_after_delete()中执行的查询会导致autoflush,这会在完成手动清理之前过早清除删除内容。 PostgreSQL中的默认引用操作是NO ACTION,即"means that if any referencing rows still exist when the constraint is checked, an error is raised"。似乎您没有推迟相关的约束,因此将立即对其进行检查。

您也许可以尝试错误消息中提出的解决方案:

@before_models_committed.connect_via(app)
def delete_all_user_folders_after_delete(sender, changes):
    for obj, operation in changes:
        if isinstance(obj, User) and operation == 'delete':
            with db.session.no_autoflush:
                fs = UserFile.query.filter_by(author_id=obj.id, parent_id=None).all()
            print('files: ', fs)
            for item in fs:
                print(item)
                # If this queries the DB, remember to disable autoflush again
                delete_file(item, True)