将现有站点更新为新的Django 1.5用户模型后,django_admin_log上的完整性错误

Integrity error on django_admin_log after updating existing site to new Django 1.5 user model

显然,在将新用户表添加到站点后,django_admin_log仍然有一个FK到auth_user表。 有没有办法解决这个问题? 我没有在升级或本地看到这个问题所以必须发生奇怪的事情。

Traceback(最近一次调用最后一次):

File"/app/.heroku/python/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
response = callback(request, *callback_args, **callback_kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.10.0.28/newrelic/api/object_wrapper.py", line 220, in call
self._nr_instance, args, kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.10.0.28/newrelic/hooks/framework_django.py", line 475, in wrapper
return wrapped(*args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/contrib/admin/options.py", line 372, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/views/decorators/cache.py", line 89, in _wrapped_view_func
response = view_func(request, *args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 202, in inner
return view(request, *args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in _wrapper
return bound_func(*args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/utils/decorators.py", line 21, in bound_func
return func(self, *args2, **kwargs2)

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/transaction.py", line 223, in inner
return func(*args, **kwargs)

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/transaction.py", line 217, in exit
self.exiting(exc_value, self.using)

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/transaction.py", line 281, in exiting
commit(using=using)

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/transaction.py", line 152, in commit
connection.commit()

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/init.py", line 241, in commit
self._commit()

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 242, in _commit
six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2])

File"/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 240, in _commit
return self.connection.commit()

File"/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.10.0.28/newrelic/hooks/database_dbapi2.py", line 68, in commit
return self._nr_connection.commit()

IntegrityError: insert or update on table"django_admin_log" violates foreign key constraint"django_admin_log_user_id_fkey"
DETAIL: Key (user_id)=(2) is not present in table"auth_user".


如果你碰到这个并且你正在使用> = 1.7:

1
2
3
./manage.py dbshell

DROP TABLE django_admin_log;

然后:

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


这是因为django_admin_log表仍包含与旧auth_user表的外键关系。

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

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

对于Django <1.7

1
$ heroku run python manage.py syncdb

而对于Django> = 1.7

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

就是这样:)

EDITED with @dustinfarris Django 1.7+ answer precision


如果您使用的是Django 1.7或更高版本,在我看来,为改变django_admin_log表添加适当的迁移是一个更好的选择。这样你就可以保留任何现有的日志条目,这可能实际上是你用过的东西。进行这样的改变要求id字段是相同的,例如,有相同的名称等

首先,您必须找出约束的名称,这可以通过进入数据库shell来完成:

1
./manage.py dbshell

然后描述django_admin_log表:

1
\d+ django_admin_log;

这将在输出中具有约束,例如:

1
"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是约束的名称,您应该将其复制以供日后使用。

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

1
./manage makemigrations --empty my_custom_auth_model

我重命名了我的新迁移(即0000_alter_admin_log_constraint.py),以便在文件名中使用一些有用的东西而不是日期戳。不要使用四个零,使用创建迁移时分配的任何内容:)

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

1
2
3
4
5
6
7
8
9
10
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。如您所见,这两个操作及其反转是彼此的反转,这意味着您也可以向后移动此迁移。

现在,您所要做的就是应用新的迁移:

1
./manage.py migrate

django_admin_log表现在应该可以再次使用,并且管理员写入它的任何内容都将起作用,而不是使用IntegrityError失败。


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

1
2
python manage.py createsuperuser    
python manage.py migrate

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

1
2
3
4
5
6
python manage.py sqlclear admin

BEGIN;
DROP TABLE"django_admin_log";

COMMIT;

所以你也可以试试。

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

看起来似乎有一个糟糕的事务,因为当你运行它时,你可以尝试完全重置你的数据库:

1
heroku pg:reset

或者你可以尝试psql进入数据库并检查/纠正产生问题的数据(这可能是它试图插入同一个用户两次):

1
heroku pg:psql