Django-DB-Migrations:无法更改表,因为它具有未决的触发事件


121

我想从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

怎么了?


1
这个问题是相似的:stackoverflow.com/questions/28429933/…并且有对我更有用的答案。
SpoonMeiser

Answers:


138

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


7
为了解决这个问题,您可以使用数据迁移,也可以手动(manage.py shell)进入并更新不符合要求的值
mgojohn 2014年

@mgojohn你怎么做?
pyramidface

1
@pyramidface如果您不太挑剔,则可以在django shell上更新null值。如果您正在寻找更正式和可测试的内容,则取决于您使用的版本。如果您使用南方,请访问:south.readthedocs.org/en/latest/tutorial/part3.html;如果您使用django的迁移,请参见此处的“数据迁移”部分:docs.djangoproject.com/en/1.8/topics/迁移
mgojohn

131

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

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

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

然后创建架构迁移:

manage.py schemamigration fooapp --auto

现在,您有两个事务,并且应该在两个步骤中进行迁移。


8
PostgreSQL可能改变了有关此类事务的行为,因为我设法在开发机(PostgreSQL 9.4)上同时进行了数据和架构更改的迁移,而服务器上却失败了(PostgreSQL 9.1)。
Bertrand Bordage 2015年

1
对我来说几乎一样。到今天为止,它可以完美地进行100多次迁移(包括约20项数据迁移),同时将唯一约束与数据迁移一起添加,从而消除了之前的重复项。PostgreSQL 10.0
LinPy粉丝

如果在迁移中使用RunPython操作进行数据迁移,则只需确保它是最后一个操作。Django知道如果RunPython操作是最后一个,则可以打开自己的事务。
Dougyfresh

1
@Dougyfresh这是django的文档功能吗?
guettli

我实际上在任何地方都看不到,这只是我观察到的东西。 docs.djangoproject.com/en/2.2/ref/migration-operations/…–
Dougyfresh

9

刚刚遇到这个问题。您还可以在模式迁移中使用db.start_transaction()和db.commit_transaction()将数据更改与模式更改分开。可能不那么干净,无法进行单独的数据迁移,但是在我的情况下,我需要架构,数据,然后再进行另一种架构迁移,因此我决定一次完成所有操作。


7
此解决方案的问题是:如果在db.commit_transaction()之后迁移失败,会发生什么情况?如果需要,我更喜欢使用三个迁移:schema-mig,data-mig,schema-mig。
guettli 2013年

5
请参阅:django.readthedocs.io/en/latest/ref/migration-operations.html 在支持DDL事务的数据库(SQLite和PostgreSQL)上,RunPython操作除了为每次迁移创建的事务外,没有自动添加任何事务。因此,例如在PostgreSQL上,应避免在同一迁移中合并模式更改和RunPython操作,否则可能会遇到诸如OperationalError的错误:不能ALTER TABLE“ mytable”,因为它有未决的触发事件。
Iasmini Gomes

5

在操作中,我将SET约束:

operations = [
    migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
    migrations.RunPython(migration_func),
    migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;'),
]


0

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

问题是您无法更改试图同时更新其值的列模式。

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


1
对我来说,运行脚本不是真正的选择。我有数据库的几个实例,连续部署过程仅称为“ manage.py migration”。这个问题已经是有效的答案,可以正常工作。
guettli
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.