将现有网站升级到新的Django 1.5用户模型后,在django_admin_log上出现完整性错误。

28
显然在将新用户表添加到网站后,django_admin_log仍然与auth_user表有一个外键。 有没有办法解决这个问题? 我在暂存或本地中没有看到这个问题,所以可能发生了一些奇怪的事情。
跟踪(最近的调用):
"File "/app/.heroku/python/lib/python2.7/site-packages/django/core/handlers/base.py",第115行,获取响应时,回调函数出错。在"/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.10.0.28/newrelic/api/object_wrapper.py"的第220行,使用了对象包装器。在"/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.10.0.28/newrelic/hooks/framework_django.py"的第475行,对函数进行了装饰。在"/app/.heroku/python/lib/python2.7/site-packages/django/contrib/admin/options.py"的第372行,对函数进行了装饰。在"/app/.heroku/python/lib/python2.7/site-packages/django/views/decorators/cache.py"的第89行,对函数进行了装饰。在"/app/.heroku/python/lib/python2.7/site-packages/django/db/transaction.py"的第217行,使用了上下文管理器。在"/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/init.py"的第241行,执行了提交操作。在"/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py"的第242行,执行了实际的提交操作并捕获了异常。最后,在"/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py"的第240行和"/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.10.0.28/newrelic/hooks/database_dbapi2.py"的第68行,对提交操作进行了装饰,并返回了异常。在表“django_admin_log”上插入或更新时,违反了外键约束“django_admin_log_user_id_fkey”,详细信息为:主键(user_id)=(2)不存在于表“auth_user”中。"
6个回答

37

如果你遇到这个问题,而且你正在使用 >=1.7 版本:

./manage.py dbshell

DROP TABLE django_admin_log;

然后:

./manage.py sqlmigrate admin 0001 | ./manage.py dbshell

在1.8.2版本中对我有效。最好能够添加它的实际功能描述。 - Frankline
对于一个使用 django 1.10.1 的新项目,我按照指示进行了删除操作,但是在最后一步,我使用了简单的 migrate 命令而不是 sqlimigrate 命令。所以整个过程是这样的:“migrate->error->drop->migrate”。 - alekosot
感谢您的解决方案,但对于我来说它没有起作用。 它会抛出一个错误:“CommandError:无法找到与应用程序'admin'中的“001”匹配的迁移。 它在INSTALLED_APPS中吗?”你能告诉我我做错了什么吗? - Mohe TheDreamy

20

这是因为django_admin_log表仍然包含一个指向旧auth_user表的外键关系。

您需要删除并重新创建该表。

$ heroku pg:psql
psql => drop table django_admin_log;

对于 Django 版本低于 1.7 的情况:
$ heroku run python manage.py syncdb

对于Django版本大于或等于1.7

$ ./manage.py sqlmigrate admin 0001 | heroku pg:psql

就是这样 :)

经@dustinfarris编辑,增加了Django 1.7+标准的精确性


8
如果您使用的是Django 1.7或更高版本,我认为为更改django_admin_log表添加适当的迁移是更好的选择。这样,您可以保留任何现有的日志条目,这实际上可能是您需要的内容。要进行此类更改,需要确保id字段相同,例如具有相同的名称等。
首先,您需要找出约束的名称,可以通过进入数据库shell来完成:
./manage.py dbshell

接下来描述 django_admin_log 表:

\d+ django_admin_log;

这将在输出中具有约束条件,类似于:
"user_id_refs_id_c0d12874" FOREIGN KEY (user_id) REFERENCES my_custom_auth_model(id) DEFERRABLE INITIALLY DEFERRED

其中my_custom_auth_model是您自定义身份验证模型所在的表的名称,user_id_refs_id_c0d12874是约束的名称,您应该将其复制以备后用。

接下来,创建一个新的迁移:

./manage makemigrations --empty my_custom_auth_model

我将我的新迁移(即0000_alter_admin_log_constraint.py)重命名为有用的东西,而不是文件名中的日期时间戳。但不要使用四个零,而要使用创建迁移时分配的任何名称 :)

在新迁移中,这是我用于操作的内容:

operations = [
    migrations.RunSQL(
        '''ALTER TABLE django_admin_log DROP CONSTRAINT user_id_refs_id_c0d12874''',
        reverse_sql='''ALTER TABLE django_admin_log ADD CONSTRAINT user_id_refs_id_c0d12874
            FOREIGN KEY (user_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED'''),
    migrations.RunSQL(
        '''ALTER TABLE django_admin_log ADD CONSTRAINT user_id_refs_id_c0d12874
            FOREIGN KEY (user_id) REFERENCES my_custom_auth_model(id) DEFERRABLE INITIALLY DEFERRED''',
        reverse_sql='''ALTER TABLE django_admin_log DROP CONSTRAINT user_id_refs_id_c0d12874'''),
]

user_id_refs_id_c0d12874替换为之前复制的任何约束名。可以看到,这两个操作及其反向操作是彼此的反函数,这意味着您也可以将此迁移向后移动。

现在,您只需要应用新的迁移即可:

./manage.py migrate

django_admin_log 表现在可以再次使用,任何写入到管理界面的东西都将正常工作,而不会因为 IntegrityError 而失败。


不是最简单的解决方案,但至少它会将您的数据保存在管理员日志中! - mennanov
我认为在迁移中硬编码约束名称是不规范的。这样做是不可移植的。 - Danilo Bargen
谢谢。我也觉得拥有迁移文件是一种方式,这对我很有帮助。 - Venkat Kotra

0

我认为管理员应用程序只安装了django_admin_log表。

python manage.py sqlclear admin

BEGIN;
DROP TABLE "django_admin_log";

COMMIT;

所以你也可以尝试一下。

python manage.py sqlclear admin | python manage.py dbshell
python manage.py syncdb

0

看起来在运行此代码时可能存在错误的事务,您可以尝试使用以下命令完全重置数据库:

heroku pg:reset

或者您可以尝试通过psql进入数据库并检查/更正创建问题的数据(很可能是它正在尝试两次插入相同的用户):

heroku pg:psql

-1

删除数据库并创建超级用户,最后运行migrate

python manage.py createsuperuser    
python manage.py migrate

对于一些项目来说,删除数据库是不可行的。 - Jaqueline Passos

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