163

我想从 TextField 中删除 null=True:

-    footer=models.TextField(null=True, blank=True)
+    footer=models.TextField(blank=True, default='')

我创建了一个模式迁移:

manage.py schemamigration fooapp --auto

由于某些页脚列包含,如果我运行迁移,NULL我会得到这个:error

django.db.utils.IntegrityError:列“页脚”包含空值

我将此添加到架构迁移中:

    for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
        sender.footer=''
        sender.save()

现在我得到:

django.db.utils.DatabaseError: cannot ALTER TABLE "fooapp_emailsender" because it has pending trigger events

怎么了?

4

8 回答 8

184

另一个原因可能是因为您尝试将列设置为NOT NULL它实际上已经具有NULL值的时间。

于 2014-02-25T16:58:06.070 回答
172

每个迁移都在一个事务中。在 PostgreSQL 中,您不能在一个事务中更新表然后更改表模式。

您需要拆分数据迁移和架构迁移。首先使用以下代码创建数据迁移:

 for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
    sender.footer=''
    sender.save()

然后创建架构迁移:

manage.py schemamigration fooapp --auto

现在您有两个事务,分两步迁移应该可以工作。

于 2012-10-11T11:06:29.343 回答
22

在操作中,我设置了 SET CONSTRAINTS:

operations = [
    migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
    migrations.RunPython(migration_func),
    migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;'),
]
于 2020-03-24T10:41:57.583 回答
16

如果要添加不可为空的字段,则需要在两个迁移中进行:

  1. AddFieldRunPython填充它
  2. AlterField将字段更改为不可为空

解释

在 PostgreSQL 和 SQLite 上,如果您有一个足够复杂的RunPython命令并在同一迁移中结合架构更改,则可能会出现此问题。例如,如果您要添加一个不可为空的字段,则典型的迁移步骤是:

  1. AddField将字段添加为可为空
  2. RunRython填充它
  3. AlterField将字段更改为不可为空

在 SQLite 和 Postgres 上,这可能会导致问题,因为整个事情是在一个事务中完成的。Django 文档
对此有一个特定的警告:

在支持 DDL 事务的数据库(SQLite 和 PostgreSQL)上,除了为每次迁移创建的事务之外,RunPython 操作不会自动添加任何事务。因此,例如,在 PostgreSQL 上,您应该避免在同一迁移中组合模式更改和 RunPython 操作,否则您可能会遇到诸如 OperationalError: cannot ALTER TABLE "mytable" 这样的错误,因为它有待处理的触发事件。

如果是这种情况,解决方案是将您的迁移分成多个迁移。通常,拆分的方法是进行第一次迁移,其中包含通过 run_python 命令向上执行的步骤,第二次迁移包含其之后的所有步骤。因此,在上述情况下,模式将是一次迁移中的 和 ,以及AddField第二次迁移中的 。RunPythonAlterField

于 2020-10-28T03:46:34.843 回答
9

刚刚遇到这个问题。您还可以在架构迁移中使用 db.start_transaction() 和 db.commit_transaction() 将数据更改与架构更改分开。可能没有单独的数据迁移那么干净,但在我的情况下,我需要架构、数据,然后是另一个架构迁移,所以我决定一次性完成。

于 2013-04-15T13:24:50.930 回答
1

您正在更改列架构。该页脚列不能再包含空白值。该列的数据库中很可能已经存储了空白值。Django 将使用 migrate 命令将数据库中的那些空白行从空白更新为现在的默认值。Django 尝试更新页脚列具有空白值的行并同时更改架构(我不确定)。

问题是您不能同时更改尝试更新值的同一列模式。

一种解决方案是删除更新架构的迁移文件。然后,运行脚本将所有这些值更新为您的默认值。然后重新运行迁移以更新架构。这样,更新已经完成。Django 迁移只是改变模式。

于 2020-04-23T20:31:08.567 回答
0

步骤 1)解决方案是从迁移文件夹中删除最新的迁移,并删除模型中最新添加的字段。

步骤 2)然后再次进行迁移和迁移

步骤 3)最后再次添加已在第一步中删除的字段

步骤 4) 然后再次 makemigration 和 migrate

问题解决了

于 2021-03-11T05:07:07.323 回答
0

就我而言,我有

  1. 添加字段
  2. 运行Python
  3. 删除字段

然后我只是将最后一个 RemoveFied 移动到新的迁移文件中,这解决了问题

于 2021-11-10T16:19:10.810 回答