Django - изменение отношения ForeignKey к OneToOne

Я использую Юг с моим приложением Django. У меня есть две модели, которые я изменяю от отношения ForeignKey к отношению OneToOneField. Когда я запускал эту миграцию в моей базе данных dev, она работала нормально. Когда миграция запускается как часть создания тестовой базы данных, последняя миграция завершается с ошибкой MySQL 1005: "Невозможно создать таблицу mydb. # Sql-3249_1d (errno: 121)". Выполнение какого-то Googling показало, что это обычно проблема с попыткой добавить ограничение с тем же именем, что и существующее ограничение. Конкретной линией миграции, с которой он выходит, является:

Отношение было изменено с:

class MyModel(models.Model):
    othermodel = models.ForeignKey(OtherModel)

к

class MyModel(models.Model):
    othermodel = models.OneToOneField(OtherModel)

который сгенерировал следующие операторы миграции:

db.alter_column('myapp_mymodel', 'othermodel_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['myapp.OtherModel'], unique=True))

db.create_unique('myapp_mymodel', ['othermodel_id'])

Но вместо отказа при вызове create_unique он не работает при вызове alter_column. Я выполнил следующую команду, чтобы увидеть, какой SQL был сгенерирован:

python manage.py migrate myapp 0010 --db-dry-run --verbosity=2

и распечатал

myapp:0010_auto__chg_field_mymodel_othermodel__add_unique_mymodel
   = ALTER TABLE `myapp_mymodel` ADD CONSTRAINT `myapp_mymodel_othermodel_id_uniq` UNIQUE (`othermodel_id`) []
   = SET FOREIGN_KEY_CHECKS=1; []
   = ALTER TABLE `myapp_mymodel` ADD CONSTRAINT `myapp_mymodel_othermodel_id_uniq` UNIQUE (`othermodel_id`) []

Кажется странным, что он пытается дважды запустить ADD CONSTRAINT, но если я удалю вызов db.create_unique, при запуске его с --db-dry-run SQL не генерируется SQL, но я все равно получаю ошибку, если я запускаю это реально.

Я здесь в затруднении, любая помощь приветствуется.

Ответы

Ответ 1

Вам вообще не нужна миграция. У отношений OneToOne и ForeignKey есть подсистема совместимой базы данных: простой столбец с другим идентификатором объекта в одной из таблиц.

Просто подделайте миграцию с помощью migrate --fake, если вы не хотите вводить ошибку в том, что говорите югу, чтобы игнорировать это изменение.

Ответ 2

Я согласен с @e-satis, что целью здесь является подделка миграции, но я предлагаю другой подход, если вы работаете с командой.

Если вы создаете миграцию, а затем --fake, все ваши члены команды должны будут запомнить и --fake. Если кто-то из них не делает этого, когда они обновляются, у вас проблемы.

Лучший подход - создать пустую миграцию, а затем перенести ее:

manage.py schemamigration yourapp --empty fake_migration_of_foreign_key_to_onetoone
manage.py migrate  # Like you always do! 

Ответ 3

В первую очередь я бы попытался добавить db.delete_unique(...) в разные места, чтобы увидеть, могу ли я его взломать.

В противном случае я разделил бы его на 3 миграции:

  • миграция схемы для добавления нового столбца для OneToOne
  • перенос данных для копирования всех значений FK из старого столбца в новый
  • миграция схемы для удаления старого столбца, который затем я вручную отредактировал, чтобы включить команду для переименования нового столбца в прежнее значение.