django.db.utils.ProgrammingError:关系已经存在

时间:2015-04-23 17:54:18

标签: python django postgresql ubuntu

我试图为新的django项目设置表(也就是说,数据库中不存在表); django版本是1.7,db后端是PostgreSQL。该项目的名称是粗鲁的。迁移尝试的结果如下:

python manage.py makemigrations crud

Migrations for 'crud':
  0001_initial.py:
    - Create model AddressPoint
    - Create model CrudPermission
    - Create model CrudUser
    - Create model LDAPGroup
    - Create model LogEntry
    - Add field ldap_groups to cruduser
    - Alter unique_together for crudpermission (1 constraint(s))

python manage.py migrate crud

Operations to perform:
  Apply all migrations: crud
Running migrations:
  Applying crud.0001_initial...Traceback (most recent call last):
  File "manage.py", line 18, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 377, 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 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/migrate.py", line 161, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 68, in migrate
    self.apply_migration(migration, fake=fake)
  File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 102, in apply_migration
    migration.apply(project_state, schema_editor)
  File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/migration.py", line 108, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/operations/models.py", line 36, in database_forwards
    schema_editor.create_model(model)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/schema.py", line 262, in create_model
    self.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/schema.py", line 103, in execute
    cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 82, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 66, in execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 94, 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 66, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "crud_crudpermission" already exists

迁移文件中的一些亮点:

dependencies = [
    ('auth', '0001_initial'),
    ('contenttypes', '0001_initial'),
]
    migrations.CreateModel(
        name='CrudPermission',
        fields=[
            ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ('_created_by', models.CharField(default=b'', max_length=64, null=True, editable=False, blank=True)),
            ('_last_updated_by', models.CharField(default=b'', max_length=64, null=True, editable=False, blank=True)),
            ('_created', models.DateTimeField(null=True, editable=False, blank=True)),
            ('_last_updated', models.DateTimeField(null=True, editable=False, blank=True)),
            ('domain', models.CharField(max_length=32, choices=[(b'town', b'Town'), (b'boe', b'BOE'), (b'police', b'Police')])),
            ('ldap_group', models.CharField(max_length=128, verbose_name=b'LDAP group')),
            ('can_add', models.BooleanField(default=False, verbose_name=b'add')),
            ('can_change', models.BooleanField(default=False, verbose_name=b'change')),
            ('restrict_change_to_own', models.BooleanField(default=False)),
            ('can_delete', models.BooleanField(default=False, verbose_name=b'delete')),
            ('restrict_delete_to_own', models.BooleanField(default=False)),
            ('models', models.ManyToManyField(to='contenttypes.ContentType', null=True, blank=True)),
        ],
        options={
            'verbose_name': 'CRUD permission',
        },
        bases=(models.Model,),
    ),
    migrations.AlterUniqueTogether(
        name='crudpermission',
        unique_together=set([('ldap_group', 'can_add', 'can_change', 'can_delete', 'domain')]),
    )

crud应用程序并不意味着实际做任何事情,但我使用另一个应用程序,所以当我尝试从该应用程序迁移时,我会触发上述问题。

我在网络上发现了其他类似问题的例子,但他们的案例似乎都没有适用,因为

  1. 问题会影响整个关系,而不仅仅是一列
  2. 我没有使用多重继承。
  3. 我应该在哪里查看底层问题?

13 个答案:

答案 0 :(得分:57)

这很好用

{{1}}

来源: - https://github.com/nijel/weblate/issues/587

答案 1 :(得分:23)

最初python manage.py migrate --fake

阅读choosing Slow Animations (⌘T) from the Debug menu

答案 2 :(得分:6)

面对类似的问题,最终删除了迁移文件夹中的所有.py文件(django 1.7自动创建一个),之后完美运行。

答案 3 :(得分:5)

在向现有模型添加几个新字段时,我遇到了类似的问题。我使用的是Django 1.9,introduced --run-syncdb选项。正在运行manage.py migrate --run-syncdb修复我的表格。

答案 4 :(得分:4)

我遇到了类似的问题,我更改了列名。我得到了与他提出的堆栈跟踪中提到的相同的错误。

这就是我的所作所为。

我先运行假迁移。然后我从 django_migrations 表中删除了它(我想要运行的迁移)条目并再次运行迁移(这次没有假)。

我发现预期的变化。

希望这有用。

答案 5 :(得分:3)

现在(我使用Django 1.9)你可以:

./ manage.py [--database DATABASE] - 假[app_label] [migration_name]

通过这种方式,您可以更准确地定位问题,并且只能伪造特定数据库上有问题的迁移。

所以,看看这个问题,你可以:

./ manage.py --database default --fake crud crud.0001_initial

答案 6 :(得分:3)

Django提供了一个--fake-initial选项,我发现该选项很有效。来自Django Migration Documentation

  

-fake-initial

     

如果所有数据库都允许Django跳过应用程序的初始迁移   由所有CreateModel创建的所有模型的名称的表格   该迁移中的操作已经存在。此选项旨在   用于首次对数据库进行迁移时使用   预先使用了迁移。但是,此选项不检查   用于匹配表名称之外的匹配数据库模式,因此   仅在确信现有架构的情况下才能安全使用   匹配您的初始迁移中记录的内容。

对于我来说,我刚刚从版本控制中拉出一个项目,并准备添加一些新的模型字段。我添加了字段,运行./manage.py makemigrations,然后尝试运行./manage.py migrate,这引发了错误,因为正如人们期望的那样,现有数据库中已经存在许多字段。

我应该做的是从版本控制中拉出项目以创建现有模型状态的快照后立即运行makemigrations。然后,运行./manage.py migrate --fake-initial将是下一步。

此后,您可以像往常一样添加makemigrations> migrate

注意::我不知道--fake-initial是否会跳过现有字段添加新字段。我选择注释掉到目前为止我已经创建的新字段,运行--fake-initial,就好像这是我从版本控制中拉出后要做的第一件事, then 在更新中添加字段中进行下一次迁移。

其他相关文档:https://docs.djangoproject.com/en/dev/topics/migrations/#initial-migrations

答案 7 :(得分:1)

我在Django 1.10项目中找到并解决了这个错误的一个特定示例,而我正在将名为member的外键字段更改为指向另一个表。我在三个不同的模型中改变它,我在所有这些模型中都遇到了这个错误。在我的第一次尝试中,我将member重命名为member_user并尝试创建一个新字段member作为指向新表的外键,但这不起作用。

我发现当我重命名member列时,它没有修改<app>_<model>_<hash>表单中的索引名称,当我尝试创建新的member列时,它尝试了创建相同的索引名称,因为名称的哈希部分是相同的。

我通过临时创建新的member_user关系并复制数据来解决问题。这创建了一个具有不同哈希的新索引。然后我删除了member并重新创建它指向新表,并与它一起使用可能存在冲突的索引名称。完成后,我运行RunPython步骤以填充新member列,并引用适用的表。我最后添加了RemoveField次迁移来清理临时member_user列。

我必须将迁移分成两个文件,因为我收到了这个错误:

  

psycopg2.OperationalError:不能ALTER TABLE“&lt; table_name&gt;”因为它有未决的触发事件

在创建数据并将其复制到member_user后,我无法在同一个迁移事务中删除member。这可能是postgres特定的限制,但通过创建另一个事务并在创建并复制member_user到第二个迁移后移动所有内容,可以轻松解决此问题。

答案 8 :(得分:1)

我在web2pyframework的{​​{1}}中发现了这个问题。

更改

models/config.py

在配置文件上

settings.base.migrate = True

问题解决了。

答案 9 :(得分:1)

我已经处理了好几年了。 可能有不同的情况:

方案1 :与原始帖子中一样,您没有表格开头。 在这种情况下,我会

  1. 在models.py中注释关系
  2. 运行python manage.py
  3. 假设现在可以成功迁移
  4. 取消注释您的内容
  5. 在步骤1中注释过,请运行python manage.py migration --fake

方案2 :多个应用: 一种可能是您可能拥有不同的应用程序,并且一个应用程序的数据模型正在使用另一应用程序中的某些表。在这种情况下,如果数据模型设计正确,则您应该只能为一个应用程序创建表(通过在setting.py中仅指定一个表),然后添加另一个应用程序并进行迁移。如果它不是精心设计,并且存在递归依赖项,那么我建议更改设计而不是进行临时修复。

方案3 :您有一些表,并且迁移时出了点问题,然后我会

  1. 将models.py恢复为原来的样子,仅引入新的 似乎已经存在于models.py中的关系。
  2. 删除迁移文件夹
  3. 运行python manage.py makemigrations
  4. 对model.py进行新的更改(如果有),并继续进行makemigrations和 照常迁移命令。

答案 10 :(得分:1)

在我的例子中,一个迁移文件被删除,一个新的自动生成,它有一个不同的名字。由于名称不同,Django 尝试应用新的迁移文件,该文件与之前应用的完全相同,现在已删除。在这两种情况下,都必须创建一个新模型,这导致 django.db.utils.ProgrammingError: relation "app_space" already exists。我试图逆转迁移,但缺少的迁移文件阻止了 django 实际逆转它。经验教训,迁移文件应该被检入 git。

这里有一些步骤可以帮助我找到问题的根源。 --fake 暂时解决了它,但在下一次迁移中发生了同样的问题。我不会推荐 --fake,除非您确定它是正确的用例。

这个 answer 对我来说真的很重要。

  1. 检查以前的迁移python manage.py showmigrations

  2. 检查 Django DB select * from django_migrations; 中应用的迁移(使用 psql 访问 postgres db 控制台:psql -h 0.0.0.0 -U <your-db-user> 然后使用目标 db \c <your-db-name>)。

  3. 我看到已应用的迁移已不在我的迁移文件夹中。

 20 | app             | 0001_initial                             | 2021-03-05 07:40:20.14602+00
 21 | app             | 0002_some_auto_name                      | 07:40:20.269775+00
 22 | app             | 0003_auto_20210318_2350 <---here         | 2021-03-18 23:50:09.064971+00

但在迁移文件夹中我有 0003_auto_20210318_2355,5 分钟后生成了相同的文件。我将迁移文件重命名为上面的名称,以便我可以将其反转。

  1. 通过传递要返回的迁移来反转迁移。

python manage.py migrate <app-name> <latest-migration-to-which-to-return>

python manage.py migrate app 0002_some_auto_name

  1. 从这里开始做正确的事情并检查到 git 的迁移。然后你就可以做makemigrationsmigrate,过上更平静的生活。

答案 11 :(得分:0)

我最近遇到了同样的问题,并在这里尝试了一些解决方案。 manage.py migrate --fake导致了"django_content_type" does not exist错误。如果共享迁移,则同样删除旧迁移也可能对其他用户造成问题。

manage.py squashmigrations命令(docs)似乎是解决此问题的理想方法。将旧的迁移压缩为单个迁移(这可以防止按顺序应用它们),并为任何其他用户保留旧的迁移。至少在我看来,它有效。

答案 12 :(得分:0)

请勿尝试使用--fake,因为这样做可能会损坏数据库。

相反,您可以备份当前数据库,重新创建它,然后应用备份。

  1. 创建备份:pg_dump -F c -v -h localhost <database_name> -f tmp/<pick_a_file_name>.psql

  2. 重新创建它:rails db:drop db:create

  3. 还原备份:pg_restore --exit-on-error --verbose --dbname=<database_name> tmp/<pick_a_file_name>.psql