Как удалить ограничение внешнего ключа в SQLAlchemy? - PullRequest
7 голосов
/ 11 марта 2010

Я использую SQLAlchemy Migrate для отслеживания изменений в базе данных и столкнулся с проблемой удаления внешнего ключа. У меня есть две таблицы, t_new - это новая таблица, а t_exists - это существующая таблица. Мне нужно добавить t_new, затем добавить внешний ключ для t_exists. Тогда я должен иметь возможность отменить операцию (вот где у меня проблемы).

t_new = sa.Table("new", meta.metadata,
    sa.Column("new_id", sa.types.Integer, primary_key=True)
)
t_exists = sa.Table("exists", meta.metadata,
    sa.Column("exists_id", sa.types.Integer, primary_key=True),
    sa.Column(
        "new_id", 
        sa.types.Integer,
        sa.ForeignKey("new.new_id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False
    )
)

Это отлично работает:

t_new.create()
t_exists.c.new_id.create()

Но это не так:

t_exists.c.new_id.drop()
t_new.drop()

Попытка удалить столбец внешнего ключа выдает ошибку: 1025, «Ошибка при переименовании». \ My_db_name \ # sql-1b0_2e6 «в». \ My_db_name \ exist '(номер ошибки: 150) »

Если я сделаю это с необработанным SQL, я могу удалить внешний ключ вручную, а затем удалить столбец, но я не смог выяснить, как удалить внешний ключ с помощью SQLAlchemy? Как я могу удалить внешний ключ, а затем столбец?

Ответы [ 4 ]

5 голосов
/ 28 марта 2011

Вы можете сделать это с sqlalchemy.migrate.

Чтобы заставить его работать, мне пришлось явно, а не имплицитно создавать ограничение внешнего ключа с помощью Column ('fk', ForeignKey ('fk_table.field')):

Увы, вместо этого:

p2 = Table('tablename',
            metadata,
            Column('id', Integer, primary_key=True),
            Column('fk', ForeignKey('fk_table.field')),
            mysql_engine='InnoDB',
           )

сделать это:

p2 = Table('tablename',
            metadata,
            Column('id', Integer, primary_key=True),
            Column('fk', Integer, index=True),
            mysql_engine='InnoDB',
            )
ForeignKeyConstraint(columns=[p2.c.fk], refcolumns=[p3.c.id]).create()

Тогда процесс удаления выглядит следующим образом:

def downgrade(migrate_engine):
     # First drop the constraint
     ForeignKeyConstraint(columns=[p2.c.fk], refcolumns=[p3.c.id]).drop()
     # Then drop the table
     p2.drop()
3 голосов
/ 11 марта 2010

Мне удалось это сделать, создав отдельный экземпляр метаданных и используя Session.execute () для запуска необработанного SQL. В идеале, было бы решение, которое использует исключительно sqlalchemy, поэтому мне не пришлось бы использовать специфичные для MySQL решения. Но на данный момент я не знаю о таком решении.

0 голосов
/ 22 февраля 2011

Я считаю, что вы можете достичь этого с помощью SQLAlchemy-Migrate. Обратите внимание, что ForeignKey находится в изолированном столбце. ForeignKeyConstraint находится на уровне таблицы и связывает столбцы вместе. Если вы посмотрите на объект ForeignKey в столбце, то увидите, что он ссылается на ForeignKeyConstraint.

Я не смог бы проверить эту идею, потому что две базы данных, которые я использую MS SQL, не поддерживаются SqlAlchemy-Migrate, а sqlite не поддерживает «таблицу изменений» для ограничений. Я заставил SQLAlchemy попытаться удалить FK с помощью удаления ограничения ссылок в таблице sqlite, чтобы оно выглядело хорошо. YMMV.

0 голосов
/ 15 марта 2010

Ну, вы можете достичь этого в sqlalchemy: просто drop() все ограничения перед drop() столбцом (теоретически, у вас может быть несколько ограничений):

def drop_column(column):
    for fk in column.table.foreign_keys:
        if fk.column == column:
            print 'deleting fk ', fk
            fk.drop()
    column.drop()

drop_column(t_exists.c.new_id)
...