【问题标题】:django.db.utils.ProgrammingError: relation already existsdjango.db.utils.ProgrammingError:关系已经存在
【发布时间】:2015-07-02 01:55:41
【问题描述】:

我正在尝试为一个新的 django 项目设置表(即,这些表在数据库中尚不存在); django 版本是 1.7,db 后端是 PostgreSQL。该项目的名称是crud。迁移尝试的结果如下:

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. 我没有使用多重继承。

接下来我应该在哪里寻找潜在问题?

【问题讨论】:

  • 你跑过syncdb吗?如果是这样,那已经在数据库中创建了表,所以这个迁移正在尝试重新创建。要跳过它,请运行 python manage.py migrate --fake
  • syncdb 只不过是一个迁移,如果没有超级用户,则会提示创建超级用户。如果他确实运行了它,迁移将不会尝试重新应用迁移。

标签: python django postgresql ubuntu


【解决方案1】:

【讨论】:

  • 我总是忘记什么是“默认”,所以我想提一下,这是django设置中DB配置文件的名称-docs.djangoproject.com/en/1.9/ref/settings/#databases
  • 使用假选项时请小心。它只是通过使存储在 db 中的迁移与本地文件夹匹配来解决问题,但是在进行下一次迁移时,事情会变得非常错误,所以我建议不要使用“假”,除非你真的了解发生了什么。跨度>
  • @max - 你所说的事情会出错是什么意思?当我遇到相同的编程错误时,我已经使用过这个虚假选项几次。到目前为止,我没有遇到任何问题。 ATM 我无法迁移,因为在我的应用程序中进行迁移后,表已经退出。突然 --fake 无法解决这个问题。
  • @Xeberdee 这个 fake 选项会让 django 假设你已经迁移了。如果碰巧有任何小东西没有迁移,那么它不会迁移它,因为您使用了 fake 选项。如果我知道唯一的变化是 django 抱怨的表,我只会使用 fake 选项,并且我会进行健全性检查以确保该表确实以相同的名称存在。我的观点是,如果你有 2 个更改,其中一个是已经存在的创建表,如果你伪造它,那么第二个更改将不会生效。
  • Showmigrations 会告诉您数据库在迁移方面的位置 - 并且迁移文件夹中有同名的文件。这些应该匹配是吗?您是说数据库实际上可能处于与它认为的不同的状态?这就是假货可以使之成为可能吗?在文档中没有太多可阅读的内容。 link
【解决方案2】:

【讨论】:

【解决方案3】:

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

【讨论】:

  • 这对我的情况有所帮助,在这种情况下,有必要为我自定义的 AUTH_USER_MODEL 创建一个新表,所以这个选项 --run-syncdb 达到了预期的结果
  • 运行 `python manage.py migrate --fake' 然后运行 ​​'manage.py migrate --run-syncdb' 对我有用
  • 文档中提到了 --run-syncdb:Allows creating tables for apps without migrations. While this isn’t recommended, the migrations framework is sometimes too slow on large projects with hundreds of models. 所以谨慎行事...
【解决方案4】:

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

【讨论】:

  • 这有什么副作用吗?
  • 在生产中迁移时会导致问题。试试这个或仅在初始迁移或开发中转储数据库
【解决方案5】:

现在(我使用的是 Django 1.9)你可以制作:

./manage.py migrate [--database DATABASE] --fake [app_label] [migration_name]

这样您可以更准确地定位问题,并且您可以仅伪造特定数据库上的有问题的迁移。

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

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

【讨论】:

  • 您缺少 manage.py 的实际命令。应该是:./manage.py migrate --database default --fake crud crud.0001_initial
  • 我遇到了一些 git 合并冲突的问题,导致必须使用不同的文件名重新应用一次迁移。我用这个python manage.py migrate --database default --fake &lt;appname&gt; 解决了这个问题。
【解决方案6】:

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

这就是我所做的。

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

变化按我的预期出现。

希望这有帮助。

【讨论】:

  • 这对我来说没有任何意义,但它确实有效。我已将 null=True 添加到一列(django==1.11)。有人可以解释它为什么起作用吗?
  • 这对我在 django==2.2 中与更改列名有关。
【解决方案7】:

Django 提供了一个--fake-initial 选项,我发现它对我的使用很有效。来自Django Migration Documentation

--假初始

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

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

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

之后,您可以照常添加 makemigrations > migrate

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

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

【讨论】:

    【解决方案8】:

    我已经处理这个问题好几年了。 可能有不同的场景:

    场景 1:与原始帖子一样,您没有表格可开始使用。 在这种情况下,我会

    1. 注释掉models.py中的关系
    2. 运行 python manage.py
    3. 假设现在成功迁移
    4. 取消注释你的内容
    5. 在第 1 步运行 python manage.py migrate --fake 中注释掉

    场景 2:多个应用: 一种可能性是您可能有不同的应用程序,并且一个应用程序的数据模型正在使用来自另一个应用程序的一些表。在这种情况下,如果数据模型设计得当,您应该能够只为一个应用程序创建表(通过在 setting.py 中仅指定一个),然后添加另一个应用程序并迁移。如果不是精心设计,存在递归依赖,我建议更改设计而不是临时修复。

    场景 3:您有一些表,但您的迁移出了点问题,那么我会

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

    【讨论】:

      【解决方案9】:

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

      我发现,当我重命名 member 列时,它并没有以 &lt;app&gt;_&lt;model&gt;_&lt;hash&gt; 的形式修改索引名称,而当我尝试创建新的 member 列时,它尝试创建相同的索引名称,因为名称的哈希部分相同。

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

      我确实不得不将我的迁移分成两个文件,因为我收到了这个错误:

      psycopg2.OperationalError: cannot ALTER TABLE "" 因为它有待处理的触发事件

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

      【讨论】:

        【解决方案10】:

        我在web2pyframeworkmodels/config.py 中发现了这个问题。

        改变

        settings.base.migrate = True

        配置文件到

        settings.base.migrate = False

        问题解决了。

        【讨论】:

          【解决方案11】:

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

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

          【讨论】:

            【解决方案12】:

            在我的例子中,一个迁移文件被删除,一个新的文件被自动生成,它有一个不同的名字。由于名称不同,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 &lt;your-db-user&gt; 然后使用目标 db \c &lt;your-db-name&gt;)。

            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 &lt;app-name&gt; &lt;latest-migration-to-which-to-return&gt;

            python manage.py migrate app 0002_some_auto_name

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

            【讨论】:

              【解决方案13】:

              对我来说,当我遇到这个异常时,我会使用 Django dbshel​​l 实用程序或任何类型的 MY_DATABASE Viewer / 交互式命令行来解决它>.

              DBShell:

              1. python manage.py dbshell
              2. ALTER TABLE [name_of_field_that_already_exists] DROP column [field_table];

              【讨论】:

                【解决方案14】:

                不要尝试使用--fake,因为这样做有损坏数据库的风险。

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

                1. 创建备份:pg_dump -F c -v -h localhost &lt;database_name&gt; -f tmp/&lt;pick_a_file_name&gt;.psql

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

                3. 恢复备份:pg_restore --exit-on-error --verbose --dbname=&lt;database_name&gt; tmp/&lt;pick_a_file_name&gt;.psql

                【讨论】:

                  猜你喜欢
                  • 2018-11-08
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-02-09
                  • 1970-01-01
                  • 2021-03-30
                  • 1970-01-01
                  • 2018-05-11
                  相关资源
                  最近更新 更多