修复 'column already exists' Django 迁移错误?

Fix 'column already exists' Django Migration Error?

当我尝试 运行 Django 迁移命令时出现 "column of relation already exists" 错误:

Operations to perform:
  Synchronize unmigrated apps: signin, django_rq, gis, staticfiles, admindocs, messages, pipeline, test_without_migrations, django_extensions
  Apply all migrations: profile, activities, contenttypes, # plus other modules...
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying activities.0002_auto_20170731_1939...Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 222, in handle
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 110, in migrate
    self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 148, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/migrations/migration.py", line 115, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/migrations/operations/fields.py", line 62, in database_forwards
    field,
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/contrib/gis/db/backends/postgis/schema.py", line 94, in add_field
    super(PostGISSchemaEditor, self).add_field(model, field)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/backends/base/schema.py", line 398, in add_field
    self.execute(sql, params)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/backends/base/schema.py", line 111, in execute
    cursor.execute(sql, params)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/srv/http/example.com/venvs/4dc40e5fc12700640a30ae0f040aa07ffc8aa1c5/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: column "country_id" of relation "travel" already exists

旅行 class 继承自活动 class:

# activities/models.py
from profile.models import Country

class Activity(models.Model):
    host = models.ForeignKey(User)
    # other fields...

    class Meta:
        abstract = True

class Travel(Activity):
    start_date = models.DateField()
    country = models.ForeignKey(Country)
    # other fields...

外键引用的国家class在另一个模块中。它本质上是一个包含代码(缩写)和 每个国家的名称:

# profile/models.py
class Country(models.Model):
    country_cd = models.CharField(max_length=2)
    descrip = models.CharField(max_length=50)

除了活动有两个迁移文件(我不太明白)之外,我在迁移文件中没有看到任何异常:

# activities/migrations/0001_initial.py
class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Travel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('name', models.CharField(max_length=256)),
                # other fields but none that reference Country
            ],
            options={
                'db_table': 'travel',
            },
        ),
    ]

# activities/migrations/0002_auto_20170731_1939.py
class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('profile', '0001_initial'),
        ('activities', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='travel',
            name='country',
            field=models.ForeignKey(to='profile.Country'),
        ),
        migrations.AddField(
            model_name='travel',
            name='host',
            field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
        ),
        # other fields...
    ]

我不明白为什么会出现此错误。我注意到我在其他声明外键关系的模型中没有这个问题。但是,在所有这些模型中,外键关系是 auth.models.User 或同一模型文件中的另一个 class。我最近读了一篇文章 Tips for Building High-Quality Django Apps at Scale,其中作者说如果你有跨应用外键,你可能会遇到 运行 迁移问题,所以问题可能与此有关。我可以在活动模块中重新创建 'Country' class 但这不会是 DRY。我不确定如何解决这个问题。

如果数据库中已经存在 travel.country 字段,则无法 运行 迁移。您可以使用 --fake 选项将迁移标记为已应用,而无需实际 运行 设置 SQL.

./manage.py migrate activities 0002_auto_20170731_1939 --fake

正如 Alasdair 所说,您不能覆盖现有列。当我做这样的事情时 - 必须删除表并使用 clear migrate 重新创建新表。

对于摘要中的 ForeignKey 或 ManyToManyField class,添加如下相关名称: related_name="%(app_label)s_%(class)s_related",

如果您还使用 related_query_name,请添加: related_query_name="%(app_label)s_%(class)ss",

如果您正在使用自定义迁移,并且您的迁移只是部分 运行 由于错误,您可能会收到此错误。

要解决它,您可以删除数据库中的列 shell (./manage.py dbshell):

ALTER TABLE myapp_mymodel DROP COLUMN your_column;

仅当该列没有数据并且是在您创建自定义迁移时意外创建的时才执行此操作。这将清除列中的所有数据,如果不这样做,可能会搞砸 DJANGO。

直接删除

 migrations.AddField(
        model_name='travel',
        name='country',
        field=models.ForeignKey(to='profile.Country'),
    ),

从您的迁移文件中,执行 manage.py migrate 就可以了。