代码之家  ›  专栏  ›  技术社区  ›  Zags

在生产Django部署中添加布尔字段

  •  1
  • Zags  · 技术社区  · 8 年前

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

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

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

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

    django.db.utils.IntegrityError:非空约束失败:myapp_mymodel.new_field

    从表面上看,这毫无意义,因为该字段具有默认值。深入研究这个问题,似乎默认值是由django逻辑单独提供的,而不是实际存储在sql级别。如果服务器没有更新的代码,则不会将该列传递给SQL进行更新,SQL将其解释为空。

    鉴于此,如何将此新的不可为空字段部署到应用程序中而不让用户收到任何错误?

    2 回复  |  直到 7 年前
        1
  •  2
  •   Zags    7 年前

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

    在部署1中,该字段需要为空(或者 NullBooleanField 或 null=True )中。您应该对此状态下的代码进行迁移,并确保如果字段的值为 None 是的。这是必要的,因为请求可以转到还没有新代码的服务器;如果这些服务器创建了模型的实例,则它们将创建字段为空的模型。

    在部署2中,将字段设置为不可为空,对此进行迁移,并删除为处理字段值为 无 是的。如果该字段没有默认值,则为第二次部署进行的迁移将需要为具有 无 在这个领域。

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

        2
  •  1
  •   Michael Tom    7 年前

    你可以从一个 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可以有空值,当读取该字段时,它将为空。如果您的代码能够处理这个问题,您就可以了,然后步骤7将所有这些空值转换为False如果新代码无法处理这些空值,则可以执行以下步骤:

    1. 添加 new_field=models.nullbooleanfield(默认值为false) 对你的模特来说
    2. 使用makemigrations创建架构迁移1
    3. 运行架构迁移1
    4. 更新生产代码
    5. 将模型更改为 new_field=models.booleanfield(默认值为false)
    6. 使用makemigrations创建架构迁移2
    7. 运行架构迁移2
    8. 更新生产代码

    *注意,这些方法只在Postgres中测试过。

        3
  •  -1
  •   Davy    8 年前

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

    当地发展环境:

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

    在生产服务器上:

    • 设置环境参数
    • 从版本控制系统中提取(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”)