2011-09-07 113 views
16

我正在使用South和我的Django应用程序。我有两个模型,我从ForeignKey关系变为OneToOneField关系。当我在我的开发数据库上运行这个迁移时,它运行良好。当迁移作为创建测试数据库的一部分运行时,最新的迁移失败并出现MySQL 1005错误:“无法创建表mydb。#sql-3249_1d(errno:121)”。做一些谷歌搜索显示,这通常是一个问题,试图添加与现有约束相同的名称的约束。在迁移它未能对特定行是:Django - 将OneKey关系更改为OneToOne

的关系变为从:

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呼叫失败,它是失败的01致电。我跑到下面的命令来查看正在发生什么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,但如果我真的运行它,仍然会出现错误。

我在这里亏本,任何帮助表示赞赏。

+1

我创建完全相同的迁移一些天前,它运行得很好。你可以用不同的数据库后端尝试相同的代码(我在PostgreSQL数据库中做过)。 另外,请检查您的南方版本。 – emyller

+0

希望我能帮忙 - 我做了改变,它生成了相同的python和SQL代码,并且迁移运行得很好,使用mysql 5.1.56 for win32。 – Hannele

+0

在South邮件列表上询问这个问题,你很可能找到答案。 –

回答

0

我想尝试的第一件事就是在各个地方添加一个db.delete_unique(...)以查看我是否可以破解它。

做不到这一点,我把它分解成3迁移:

  1. 模式迁移到添加新列的OneToOne
  2. 数据迁移从旧列到复制所有FK值新
  3. 模式迁移删除旧的列,然后我会手动编辑,包括一个命令重新命名新列与旧的列相同。
11

实际上根本不需要迁移。 OneToOne和ForeignKey关系在钩子下有一个兼容的数据库模式:一个简单的列,另一个对象ID在一个表中。

假如你不想让南方人忽视这种变化,那么只需假冒移民migrate --fake即可。

+0

如果您完全怀疑@ e-satis是否正确,请从代码('django.db.models.fields.related')中获取这些资讯:“OneToOneField基本上与ForeignKey相同,除了它总是带有一个“唯一”约束“并且注意OneToOne实际上只是从ForeignKey继承而来,只做了一些小的调整。 – mlissner

+0

准确地说,将字段从ForeignKey更改为OneToOneField对数据库(至少在那些支持约束的情况下)有影响,不应该跳过:ForeignKey不唯一,而OneToOneField是。在Django 1.8中 - 在mysql后端使用本地命令'makemigrations' - 我没有任何问题。迁移正确删除了数据库级别字段中以前的非唯一索引,并设置了新的唯一索引。 – baxeico

1

我同意@ e-satis这里的目标是伪造一个迁移,但是如果你和一个团队一起工作,我建议采用不同的方法。

如果你创建一个迁移然后--fake它,你所有的团队成员也需要记住--fake它。如果他们中的任何一个在升级时都没有这样做,那就麻烦了。

更好的方法是创建一个空的迁移,然后迁移它:

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