在生产Django部署中添加不可为空的字段

问题描述 投票:1回答:2

我有一个带有PostgreSQL数据库的生产Django部署(Django 1.11)。我想在我的一个模型中添加一个不可为空的字段:

class MyModel(models.Model):
    new_field = models.BooleanField(default=False)

为了部署,我需要更新服务器上的代码或首先运行迁移,但由于这是一个生产部署,请求可以(并且将会)发生在我更新数据库和更新服务器之间。如果我先更新服务器,我会得到一个OperationalError no such column,所以我显然需要先更新数据库。

但是,当我首先更新数据库时,在使用新代码更新之前,我从服务器上发出的请求中收到以下错误:

django.db.utils.IntegrityError:NOT NULL约束失败:myapp_mymodel.new_field

从表面上看,这没有任何意义,因为该字段具有默认值。进一步深入研究,似乎默认值仅由Django逻辑提供,而不是实际存储在SQL级别。如果服务器没有更新的代码,则它不会将列传递给SQL以进行更新,而SQL将其解释为NULL。

鉴于此,如何在不让用户收到任何错误的情况下将这个新的非可空字段部署到我的应用程序?

django deployment django-migrations
2个回答
2
投票

迁移应始终在部署开始时运行,否则您会遇到其他问题。此问题的解决方案是将更改拆分为两个部署。

在部署1中,字段需要可以为空(NullBooleanFieldnull=True)。您应该在此状态下对代码进行迁移,并确保如果字段的值为None,则其余代码不会崩溃。这是必要的,因为请求可以发送到尚未拥有新代码的服务器;如果这些服务器创建模型的实例,则它们将创建该字段为null。

在部署2中,您将字段设置为不可为空,为此进行迁移,并删除您编写的任何额外代码以处理字段值为None的情况。如果该字段没有默认值,则为第二次部署进行的迁移将需要在此字段中填写具有None的对象的值。

虽然看起来有点不同,但还需要两种部署技术来安全地删除字段。在第一次部署中,您将从模型文件中删除该字段,并从代码中删除对它的所有引用,但不要部署默认迁移以删除该字段。相反,部署1具有自定义迁移,可将字段设置为可空。然后,在部署2中,部署迁移以实际从数据库中删除该字段。


1
投票

你可以从NullBooleanField开始:

  1. new_field = models.NullBooleanField(default=False)添加到您的模型中
  2. 使用makemigrations创建架构迁移1
  3. 改变模型有new_field = models.BooleanField(default=False)
  4. 使用makemigrations创建架构迁移2
  5. 运行架构迁移1
  6. 更新生产代码
  7. 运行架构迁移2

如果旧的生产代码在步骤5和6之间写入表,则将写入空值new_field。在步骤6和7之间将有一段时间,其中BooleanField可以有空值,并且当读取该字段时,它将为null。如果你的代码可以处理这个问题,你就可以了,然后第7步将所有这些空值转换为False。如果新代码无法处理这些空值,则可以执行以下步骤:

  1. new_field = models.NullBooleanField(default=False)添加到您的模型中
  2. 使用makemigrations创建架构迁移1
  3. 运行架构迁移1
  4. 更新生产代码
  5. 改变模型有new_field = models.BooleanField(default=False)
  6. 使用makemigrations创建架构迁移2
  7. 运行架构迁移2
  8. 更新生产代码

*请注意,这些方法仅使用Postgres进行测试。


-1
投票

通常,django升级过程如下所示:

当地发展ENV:

  • 在本地更改您的模型
  • 迁移模型(python manage.py makemigrations)
  • 在本地测试您的更改
  • 提交并推送您对(git)服务器的更改

在生产服务器上:

  • 设置ENV参数
  • 从您的版本控制系统中拉出(git fetch --all; git reset --hard origin / master)
  • 更新python依赖项(例如pip install -r requirements.txt)
  • 迁移(manage.py migrate_schemas)
  • 更新静态文件(python manage.py collectstatic)
  • 重启django服务器(取决于服务器,但可能是'python manage.py runserver')
© www.soinside.com 2019 - 2024. All rights reserved.