Как мне определить FK и отношения SQLAlchemy, чтобы разрешить каскадное удаление базы данных? - PullRequest
0 голосов
/ 28 ноября 2018

Как определить ForeignKey и отношение таким образом, чтобы можно было отключить поведение FK-обнуления SQLAlchemy?Документация здесь , кажется, описывает использование passive_deletes=True, чтобы разрешить каскадное удаление базы данных, но только в контексте определения свойства отношения cascade , задокументированного здесь , свойствакоторый, как мне кажется, определяет, как SQLAlchemy будет выполнять само каскадное удаление, , которое явно описывается как более медленное, чем каскадное удаление ядра СУБД в этом разделе (см. зеленое поле с названием Каскад «удаления» на уровне ORM против уровня «ВНЕШНИЙ КЛЮЧ» Каскад «ON DELETE» ).

Чтобы использовать каскадное удаление базы данных, мы должны сделать следующее?

  1. определить ondelete="CASCADE" в столбце ForeignKey,
  2. определить passive_deletes=True в тех же отношениях,
  3. И определитьcascade="delete, delete-orphan" параметр для всех отношений между объектами?

Это шаг 3, который, по-моему, смущен: похоже, он определяет каскад для SQLAlchemy, а не разрешает базы данныхе выполнить собственное удаление.Но SQLAlchemy, похоже, хочет обнулить все зависимые внешние ключи до , когда база данных может получить возможность каскадного удаления.Мне нужно отключить это поведение, но passive_deletes=True, кажется, не делает это самостоятельно.

(поздний) ответ здесь явно решает мою проблему, но она не работает.Он заявляет:

Здесь есть важное предупреждение.Обратите внимание, как у меня есть отношения, указанные с passive_deletes=True?Если у вас этого нет, все это не будет работать.Это потому, что по умолчанию при удалении родительской записи SqlAlchemy делает что-то действительно странное.Он устанавливает внешние ключи всех дочерних строк в NULL.Таким образом, если вы удалите строку из parent_table, где id = 5, то она в основном будет выполняться UPDATE child_table SET parent_id = NULL WHERE parent_id = 5

В моем коде

class Annotation(SearchableMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    locked = db.Column(db.Boolean, index=True, default=False)
    active = db.Column(db.Boolean, default=True)

    HEAD = db.relationship("Edit",
            primaryjoin="and_(Edit.current==True,"
            "Edit.annotation_id==Annotation.id)", uselist=False,
            lazy="joined", passive_deletes=True)

    edits = db.relationship("Edit",
            primaryjoin="and_(Edit.annotation_id==Annotation.id,"
                "Edit.approved==True)", lazy="joined", passive_deletes=True)
    history = db.relationship("Edit",
            primaryjoin="and_(Edit.annotation_id==Annotation.id,"
                "Edit.approved==True)", lazy="dynamic", passive_deletes=True)
    all_edits = db.relationship("Edit",
            primaryjoin="Edit.annotation_id==Annotation.id", lazy="dynamic",
            passive_deletes=True)

class Edit(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    edit_num = db.Column(db.Integer, default=0)
    approved = db.Column(db.Boolean, default=False, index=True)
    rejected = db.Column(db.Boolean, default=False, index=True)
    annotation_id = db.Column(db.Integer,
            db.ForeignKey("annotation.id", ondelete="CASCADE"), index=True)
    hash_id = db.Column(db.String(40), index=True)
    current = db.Column(db.Boolean, default=False, index=True, passive_deletes=True)

    annotation = db.relationship("Annotation", foreign_keys=[annotation_id])
    previous = db.relationship("Edit",
            primaryjoin="and_(remote(Edit.annotation_id)==foreign(Edit.annotation_id),"
            "remote(Edit.edit_num)==foreign(Edit.edit_num-1))")
    priors = db.relationship("Edit",
            primaryjoin="and_(remote(Edit.annotation_id)==foreign(Edit.annotation_id),"
            "remote(Edit.edit_num)<=foreign(Edit.edit_num-1))",
            uselist=True, passive_deletes=True)

просто установите passive_deletes=Trueродительские отношения не работают .Я также подумал, что, возможно, это вызвано отношениями ребенка с его братьями и сестрами (отношения Edit.previous и Edit.priors), но установка passive_deletes=True для этих двух отношений не решает проблему, иэто вызывает следующие предупреждения, когда я просто запускаю Edit.query.get(n):

/ home / malan / projects / icc / icc / venv / lib / python3.7 / site-packages / sqlalchemy / orm /Relationss.py:1790: SAWarning: В Edit.previous «passive_deletes» обычно настраивается только для отношений «один ко многим», «один к одному», «многие ко многим».% self)

/ home / malan / projects / icc / icc / venv / lib / python3.7 / site-packages / sqlalchemy / orm / relationss.py: 1790: SAWarning: On Edit.priors, 'passive_deletes 'обычно настраивается только на отношения «один ко многим», «один к одному», «многие ко многим».% self)

На самом деле я нашел этот интересный вопрос 2015 года, на который никогда не было ответа.В ней подробно описана неудачная попытка выполнить код документации.

1 Ответ

0 голосов
/ 29 ноября 2018

Кажется, что после тщательной попытки проанализировать мои отношения, я обнаружил проблему.

Во-первых, я отмечу, passive_deletes=True является необходимым необходимым параметром.Вы не должны вообще определять cascade, чтобы воспользоваться преимуществами каскадной системы базы данных.

Что еще более важно, моя проблема, похоже, возникла из моего дерева зависимостей внешних ключей.У меня был каскад, который выглядел так:

       Annotation
      /     |    \ 
   Vote    Edit   annotation_followers
           /  \ 
    EditVote   tags

Где ondelete="CASCADE" было определено для каждого столбца parent_id в каждом дочернем классе.До тех пор, пока я не установил passive_deletes для всех дочерних элементов в графе, поведение обнуления продолжало вести себя неправильно.

Для тех, кто сталкивается с подобной проблемой, мой совет: тщательно проанализируйте все ваших пересекающихся отношений и определите passive_deletes=True для всех из них, что это имеет смысл.

Тем не менее, у меня все еще есть сложности, над которыми я работаю;например, в таблице «многие ко многим» идентификаторы даже не обнуляются.Возможен следующий вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...