IntegrityError: 在从Postgres恢复的转储后,所有带有ForeignKey的模型/字段中的列“id”中存在空值。

25

我在尝试使用Heroku的Postgres数据存储时遇到了问题,它是从我本地的Postgres数据库还原而来的。使用还原的Postgres数据库,Django能够正常运行。它检索所有对象并使用它们的字段、主键等,没有任何问题。

但当涉及写入数据库时,无论是什么模型,我都会得到相同的错误。

psycopg2.IntegrityError: null value in column "id" violates not-null constraint

当我重置Heroku数据库并从空白状态创建对象时,就没有问题了。但如果我尝试在还原的数据库上创建任何对象,我总是会得到这个 null value in column "id" violates not-null constraint 错误。


这里是从尝试在Django Admin中创建基本模型的堆栈跟踪的复制/粘贴版本。我选择了这个模型示例,因为没有与创建它相关的其他代码。没有信号或任何东西。

Django版本:2.0 Python版本:3.6.3

Traceback:

发生了完整性错误,导致无法向数据库添加某些数据,详细信息显示缺少“id”列的值。这个错误可能是由于在执行SQL语句时传入了空值而引起的。

从堆栈跟踪中可以看出,这个错误发生在每个模型上,而不仅仅是这个[非常基本的]模型。

class RaceClass(models.Model):
    title = models.CharField(max_length=140)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['title']

以下是我如何将本地数据恢复到heroku上:

我使用以下命令将我的本地Postgres数据库(版本10.0)导出:

PGPASSWORD=mypassword pg_dump -Fc --no-acl --no-owner -h localhost -U myuser mydb > mydb.dump

然后使用命令将其上传到AWS,并将其还原到Heroku上的Postgres数据存储库(版本9.6.5):

heroku pg:backups:restore 'https://s3.amazonaws.com/me/items/3H0q/mydb.dump' DATABASE_URL

这些内容直接来自Heroku文档:https://devcenter.heroku.com/articles/heroku-postgres-import-export


顺便提一下,我在本地使用的是Postgres 10.0版本,而Heroku Datastore则是9.6.5。


请您提供完整的堆栈跟踪信息以及出错时运行的代码(无论您尝试保存哪个模型),以及相关的模型类。从这些信息来看,问题似乎不在于数据库恢复,而是在于您尝试写入数据库的内容。 - solarissmoke
@solarissmoke 添加了堆栈跟踪和模型代码。我选择了最基本的一个,因为所有的问题都会发生。希望你能帮忙! - taylor
3个回答

15
我相当确定这是因为您正在从Postgres 10导出并导入到9。它并没有完全失败,但某些模式定义(在本例中是自动递增的ID字段)未被正确导入。
我可以想到两个选项:
1.尝试转储原始SQL而不是自定义格式:
PGPASSWORD=mypassword pg_dump --no-acl --no-owner -h localhost -U myuser mydb > mydb.sql

您无法使用pg_restore来加载此内容,而是必须手动使用psql运行查询。像这样的东西应该可以工作:

heroku pg:psql < mydb.sql

这里的注意事项是您需要先清空现有的数据库。

  • 如果这也失败了,那么您需要从与要导入的Postgres主要版本相同的版本中进行导出。


  • 如果您没有在相应的模型上手动设置id = models.AutoField()属性,则此内容是100%正确的。 - Shezan Kazi

    8
    关键错误在于:

    我在本地使用的是版本为10.0的Postgres,而Heroku数据存储是9.6.5

    这是一个潜在的问题。我建议尝试在两个平台上使用相同的版本,至少应该是相同的主要版本。
    对于这两个版本,我想到的是,在Postgres 10中引入了标准SQL的IDENTITY,它们旨在大量替换序列列。由于你没有披露表定义,因此我只能猜测。Postgres 10中的IDENTITY特性无法转换回Postgres 9.6,这很可能解释了错误消息中违反NULL值的原因。
    相关内容:

    0

    我最近遇到了同样的问题,以下是为我解决问题的方法:

    1. 创建新数据库
    2. 使用Django manage.py将我的数据库数据导出,并在应用所有迁移后将其还原到新数据库中。

      python manage.py dumpdata --exclude auth.permission --exclude contenttypes --indent 2 > db.json

    3. 还原备份

      python manage.py loaddata db.json


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接