Почему я получаю sqlalchemy.exc.IntegrityError - PullRequest
0 голосов
/ 08 октября 2018

Я столкнулся с ошибкой, смысл ведьмы не могу понять:

Я пишу в модели:

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', но я получил ошибку, потому что она уже работала после удаления, хотя онабыл назван «до».Я видел это, добавляя вывод сообщения в консоль и не видя этого сообщения в консоли, пока не получил ошибку.

Затем я попытался использовать сигналы 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 голосов
/ 08 октября 2018

Запрос, выполненный в delete_all_user_folders_after_delete(), вызывает autoflush , который преждевременно сбрасывает удаления перед выполнением ручной очистки.Ссылочное действие по умолчанию в PostgreSQL: NO ACTION, что означает ", если при проверке ограничения какие-либо ссылочные строки все еще существуют, возникает ошибка" .Казалось бы, вы не отложили рассматриваемое ограничение, поэтому оно проверяется немедленно.

Возможно, вы могли бы попробовать решение, предложенное в сообщении об ошибке:

@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)
...