Django在创建表时出现MySQL错误

35

我正在使用MySQL数据库构建Django应用程序。当我第一次运行'python manage.py migrate'时,一些表格被成功创建,但随后出现了一些错误。 引发的错误是:

django.db.utils.IntegrityError: (1215, 'Cannot add foreign key constraint')

当我运行这个MySQL命令 -

SHOW ENGINE INNODB STATUS\G,

得到以下结果 >>>

2015-02-17 14:33:17 7f10891cf700 Error in foreign key constraint of table movie_store/#sql-4f1_66:
 FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`):
Cannot resolve table name close to:
 (`id`)

完整的回溯如下:

Creating tables...
    Creating table users
    Creating table merchant
    Creating table celery_taskmeta
    Creating table celery_tasksetmeta
    Creating table djcelery_intervalschedule
    Creating table djcelery_crontabschedule
    Creating table djcelery_periodictasks
    Creating table djcelery_periodictask
    Creating table djcelery_workerstate
    Creating table djcelery_taskstate
    Creating table post_office_email
    Creating table post_office_log
    Creating table post_office_emailtemplate
    Creating table post_office_attachment
    Running deferred SQL...
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 390, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 441, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/migrate.py", line 173, in handle
    created_models = self.sync_apps(connection, executor.loader.unmigrated_apps)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/migrate.py", line 309, in sync_apps
    cursor.execute(statement)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 80, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 95, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 63, in execute
    return self.cursor.execute(sql)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 124, in execute
    return self.cursor.execute(query, args)
  File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
django.db.utils.IntegrityError: (1215, 'Cannot add foreign key constraint')

1
你可能需要包含运行此文件的模型文件。 - warath-coder
我认为你没有在INSTALLED_APPS中包含'django.contrib.auth'。 - Daniel Roseman
我有这两个中间件:'django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.auth.middleware.SessionAuthenticationMiddleware'。 - Denny
1
@Denny,请将django.contrib.auth添加到您的INSTALLED_APPS而不是MIDDLEWARE_CLASSES中。 - Jahongir Rahmonov
1
@Denny- 你解决了这个问题吗? - Praful Bagai
显示剩余5条评论
11个回答

40

这将会起作用。

python manage.py migrate auth
python manage.py migrate

之前已经有其他迁移在认证之前运行了,因此这将确保“authtools”的迁移首先运行。


4
请考虑编辑您的帖子,增加关于代码的功能和解决问题的原因的更多解释。即使代码可以正常工作,如果答案主要只包含代码,通常也无法帮助提问者理解他们的问题。 - SuperBiasedMan
1
@JamesLin 我在运行单元测试时也遇到了这个问题。然而,unittest每次运行测试时都会重新创建模式,所以我仍然没有找到解决方案。不过,我有一个小技巧可以解决这个问题:
  1. 运行单元测试(第一次): $python manage.py test
这将创建测试数据库,但在迁移时失败。 2. 然后使用 --keepdb 重新运行测试`$python manage.py test --keepdb`这样你就可以运行测试了,但当然这不是回归测试的正确方式。
- hiennt
@hiennt:你的解决方案对我也起作用了。我在单元测试中遇到了这个错误。但是你有没有找到更好的方法来解决这个问题? - sudshekhar
@sudshekhar 我也遇到了同样的问题。 - neeraj
运行得非常好。谢谢。 - Arpan Srivastava
我也试过了,有效! - Tiago Martins Peres

11

我在使用时遇到了这个问题:

$ python manage.py test
如果你的模型有一个字段是指向 django.contrib.auth.models.UserForeignkey,但却没有对这些模型进行迁移,这将会导致问题。
如果你开启了 --keepdb 参数,你会发现缺少了 auth_user 表和其他一些 Django 管理表。

我们来追踪一下整个问题:

运行:

$ python manage.py test --verbosity=3

在执行延迟的 SQL 语句后,您可以看到引发了外键约束异常。

正在运行延迟的 SQL 语句...

延迟的 SQL 语句类似于

"ALTER TABLE xxx ADD CONSTRAINT xx FOREIGN KEY (x) REFERENCES auth_user"

请查看django/core/management/commands/migrate.py的源代码:

for statement in deferred_sql:
    cursor.execute(statement)

defered_sql来自于manifest.items()的循环,

manifest来自于all_models

all_models来自于app_labels中的app_config.label

这是传递的参数。

self.sync_apps(connection, executor.loader.unmigrated_apps)
因此,executor.loader.unmigrated_apps将包含未迁移的应用程序的标签,如果您恰好有指向Django的auth_user的Foreignkey,则会导致Foreignkey约束错误,因为在那时还没有名为auth_user的表。
解决方案:
假设app是包含这些Foreignkey属性类的模块:
$ python manage.py migrate auth
$ python manage.py migrate
$ python manage.py makemigrations app

如果你的其他模块依赖于 app 模块,假设数据库表与 app 模块具有相同的字段,则需要执行以下操作:

$ python manage.py make migrate app --fake

1
+1 是为了努力挖掘源代码。但是这个解决方案如何帮助manage.py test?通过交换 makemigrations 的顺序吗? - Diansheng
@Sean =。= 我的意思是,在运行python manage.py test之前,我们应该为那些包含对Django默认模型的Foreignkey的应用程序模型进行makemigrations。例如,一个指向django.contrib.auth.User的Foreignkey。否则,它会引发异常。举个例子,如果你丢失了应用程序的迁移文件夹,你将无法成功运行python manage.py test - carton.swing

9

你是否为所有应用程序创建了迁移?如果没有,你可能会遇到数据库表按错误顺序创建的问题,这会导致出现此错误。

如果你有一个现有的Django 1.7项目,则需要创建初始迁移文件,然后模拟初始迁移,如此处所述。

https://docs.djangoproject.com/en/1.8/topics/migrations/#adding-migrations-to-apps

使用以下命令创建迁移:

$ python manage.py make migrations your_app_label

然后伪造应用程序

$  python manage.py migrate --fake-initial your_app_label

4

我遇到了与外键'author_id'相同的问题。

解决方案是将名称更改为

author = models.ForeignKey(User, related_name='+')

为了

writer = models.ForeignKey(User, related_name='+')

所以尝试将字段名称更改为与其他不同的名称。

group

2

我在尝试在BitBucket/Pipelines中设置CI时遇到了同样的错误。问题是我没有将迁移文件夹提交到我们的git仓库中,因为Pipelines每次都会从头开始重建所有内容,导致单元测试无法启动。

当您执行以下操作时,将创建迁移文件夹:

python manage.py makemigrations
python manage.py makemigrations <module_name>

我需要在运行makemigrations/migrate步骤并确保我们的非测试代码正常工作后,才能使我的测试正常工作。

看起来:

python manage.py test 

如果迁移文件不存在,它将尝试生成迁移,但有时不能正确获取依赖关系,因此您需要确保将自动生成的代码提交到迁移文件夹中以备份。

有关 Django 迁移的更多详细信息,请参见https://docs.djangoproject.com/en/1.11/topics/migrations/


1

确保外键和主键类型相同。

外键必须与外部表的主键类型相同。我在外部表中有一个bigint,django不知道如何自动创建一个bigint外键。

通过运行以下命令来调查迁移失败的原因:

python manage.py sqlmigrate {app_name} {migration_name}

在工作台中运行此命令,您将看到故障背后的真实错误。

django.db.utils.IntegrityError: (1215,'无法添加外键约束')


0

在针对 MySQL 数据库运行 Django 库的测试时,我遇到了类似的问题(以避免与 CentOS 7 不兼容的 Django 2.2)。这与 carton.swing 的答案 所解决的问题类似,但采取了不同的解决方法。

关于我正在测试的库,有几点需要注意:

  • 未定义任何模型,但测试套件定义了用于测试目的的模型
  • 测试套件依赖于外键模型,它们并未定义,具体来说是 auth.User 模型。

在查看一个旧的 Django ticket之后,我注意到了这个回答:

你的问题是未迁移的应用程序(authtoken)依赖于已迁移的应用程序(main)。这是一个众所周知的错误。

(我找不到其他关于这个是“众所周知的禁忌”的参考资料。)由于测试套件定义了一些模型,并且还使用了Django提供的auth.User,我猜测测试运行程序(在这种情况下是pytest)迁移了在测试套件中定义的模型,但没有迁移auth.User。为了测试这一点,我关闭了我的测试套件上的迁移(对于pytest-django,这只需要添加一个--no-migrations标志),这解决了问题。


0

遇到了类似的情况,出现了

django.db.utils.OperationalError: (1824, "Failed to open the referenced table 'auth_user'")

首先,我通过确保所有迁移都正确完成,每个应用程序都有其相应的迁移文件夹以及其中的__init__.py文件来解决了这个问题。

之后,我在数据库中的另一张表格上遇到了类似的问题,引发了另一个错误,这阻止了我启动测试。我通过删除django_migrations表中的所有记录,删除所有迁移文件(如果您同意),然后运行以下命令来解决它:

python manage.py makemigrations

python manage.py migrate --fake

所有关于迁移的烦恼都解决了 :)


-1

我曾经遇到过同样的问题,后来发现 Django 不知何故升级到了 v1.8,于是我立即将其降级到了 v1.7,问题得以解决。


-3
如果上述方法不起作用并且您不需要InnoDB,那么默认使用MYISAM,因为它没有同样级别的引用完整性。
DATABASES = { 
  'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'name',                      
    'USER': 'user',     
    'PASSWORD': 'password',
    'OPTIONS': {
           "init_command": "SET storage_engine=MYISAM",
    }   
  }   
}

现在使用MyISAM应该被视为有害的。 - spacediver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接