django.db.utils.IntegrityError: 重复键值违反唯一约束条件 "django_migrations_pkey"

20

我有一个Django模型SessionType,定义类似于以下内容:

from django import models


class SessionType(models.Model):
    class Meta:
        ordering = ['title']
    title = models.CharField(max_length=255, unique=True)

起初,没有unique=True的限制;我刚刚添加了它,并运行了python manage.py makemigrations。这导致了以下迁移(0163_auto_20180627_1309.py):
# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2018-06-27 20:09
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('lucy_web', '0162_merge_20180531_0009'),
    ]

    operations = [
        migrations.AlterField(
            model_name='sessiontype',
            name='title',
            field=models.CharField(max_length=255, unique=True),
        ),
    ]

然而,当我尝试运行python manage.py migrate时,出现以下错误:

django.db.utils.IntegrityError: 重复键违反唯一约束条件“django_migrations_pkey” 详细信息:(id)=(326) 的键已经存在。

以下是命令和完整的跟踪信息:

(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py makemigrations
Migrations for 'lucy_web':
  lucy_web/migrations/0163_auto_20180627_1309.py
    - Alter field title on sessiontype
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auditlog, auth, contenttypes, defender, lucy_web, oauth2_provider, otp_static, otp_totp, sessions, two_factor
Running migrations:
  Applying lucy_web.0163_auto_20180627_1309...Traceback (most recent call last):
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
psycopg2.IntegrityError: duplicate key value violates unique constraint "django_migrations_pkey"
DETAIL:  Key (id)=(326) already exists.


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 28, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 356, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 204, in handle
    fake_initial=fake_initial,
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 115, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 145, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 250, in apply_migration
    self.recorder.record_applied(migration.app_label, migration.name)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/recorder.py", line 73, in record_applied
    self.migration_qs.create(app=app, name=name)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/query.py", line 394, in create
    obj.save(force_insert=True, using=self.db)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/base.py", line 808, in save
    force_update=force_update, update_fields=update_fields)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/base.py", line 838, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/base.py", line 924, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/base.py", line 963, in _do_insert
    using=using, raw=raw)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/query.py", line 1076, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1112, in execute_sql
    cursor.execute(sql, params)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: duplicate key value violates unique constraint "django_migrations_pkey"
DETAIL:  Key (id)=(326) already exists.

查看数据库,我发现有另一个主键为326的迁移:

enter image description here

那个迁移文件,0161_auto_20180530_2140.py,还包含对SessionType模型的AlterField操作:

# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2018-05-31 04:40
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('lucy_web', '0160_merge_20180524_1507'),
    ]

    operations = [
        migrations.AlterField(
            model_name='sessiontype',
            name='description',
            field=models.TextField(blank=True),
        ),
        migrations.AlterField(
            model_name='sessiontype',
            name='short_description',
            field=models.TextField(blank=True),
        ),
    ]

django db migration failed with postgres之后,我尝试运行该命令

ALTER SEQUENCE django_migrations_id_seq RESTART WITH 329;

就像这样:

enter image description here

然而,现在当我尝试进行迁移时,我遇到了另一个错误,即某个唯一约束已经存在:

(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auditlog, auth, contenttypes, defender, lucy_web, oauth2_provider, otp_static, otp_totp, sessions, two_factor
Running migrations:
  Applying lucy_web.0163_auto_20180627_1309...Traceback (most recent call last):
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "lucy_web_sessiontype_title_c207e4f8_uniq" already exists


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 28, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 356, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 204, in handle
    fake_initial=fake_initial,
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 115, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 145, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/migration.py", line 129, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/migrations/operations/fields.py", line 221, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 515, in alter_field
    old_db_params, new_db_params, strict)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/postgresql/schema.py", line 112, in _alter_field
    new_db_params, strict,
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 719, in _alter_field
    self.execute(self._create_unique_sql(model, [new_field.column]))
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 120, in execute
    cursor.execute(sql, params)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "lucy_web_sessiontype_title_c207e4f8_uniq" already exists

我该如何解决这个问题?是删除唯一约束并重新运行迁移吗?

4个回答

72

这个修复方法适用于我的PostgreSQL数据库

打开Django shell

python manage.py shell
运行以下Python代码以重置id。
from django.db import connections

query = "SELECT setval('django_migrations_id_seq', (SELECT MAX(id) FROM django_migrations))"
cursor = connections['default'].cursor()
cursor.execute(query) 
row = cursor.fetchone()

3
与标记答案相比,这是一个更好的答案,并且运作良好。 - Dinesh
2
这里简单说明一下这个答案的含义,因为虽然它很好,但是有点简洁:我认为问题在于 Django 迁移表中有两条记录具有相同的 ID。此命令将其中一条记录设置为新的 ID,假设 ID 是连续编号的。完成后,所有记录都应该具有唯一的 ID,当您运行迁移时就不会再出现错误了。 - MagicLAMP
这对我非常有效。顺便提一下,它可以应用于所有表,不仅限于django_migrations。 - AmineBTG

6

重复运行迁移命令,直到错误消失。 每次尝试时,它会试图增加id(pk)的值。 一旦增量达到现有id的最大值,该命令将成功运行。


1
聪明的解决方案!我只需要运行三次就可以看到id的“偏移”。对于对象较少的数据库非常好!想象一下如果“违反的id”的数量很多会怎样! - Laenka-Oss

1
重新启动索引后,我确实只是删除/丢弃了导致“已存在”错误的约束和索引,并成功进行了迁移。
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auditlog, auth, contenttypes, defender, lucy_web, oauth2_provider, otp_static, otp_totp, sessions, two_factor
Running migrations:
  Applying lucy_web.0163_auto_20180627_1309... OK

0

我使用以下查询修复了我的Postgres数据库:

  1. 使用./manage.py dbshell进入您的DB shell
  2. 运行SELECT id FROM "django_admin_log" ORDER BY id DESC LIMIT 1;并记录输出(应该是一个整数,如326)
  3. 运行SELECT setval('django_admin_log_id_seq', LASTID + 1);并用先前命令得到的整数替换LASTID

选择 setval('django_admin_log_id_seq', (SELECT id FROM "django_admin_log" ORDER BY id DESC LIMIT 1) + 1 ); - ChuckCottrill

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