是否可以重新创建从 Django 模型中意外删除的 table 字段,而无需拆除所有迁移?

Is it possible to recreate a table field that was accidentally removed from Django Model, without tearing down all migrations?

假设以下模型:

class Country(models.Model):
    name = models.TextField(null=True, blank=True)
    continent = models.TextField(null=True, blank=True)
    population = models.PositiveIntegerField(null=True, blank=True) 

然后我:

  1. models.py 中删除字段 population
  2. 创建迁移:python manage.py makemigrations countries_app
  3. 执行迁移,将字段标记为已删除:python3 manage.py migrate countries_app

这是迁移文件 0006,它是上次创建的迁移 (0005) 的序列:

class Migration(migrations.Migration):

    dependencies = [
        ('countries_app', '0005_auto_20210723_0007'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='country',
            name='population',
        ),
    ]

现在,我的数据库中没有 population 字段,但我意识到从 Country 模型中删除 population 字段是一个错误。

为了让事情恢复正常,我在模型上再次定义了该字段,我取消了迁移 0006,并且还删除了 0006 迁移文件,其中定义了删除的领域,我也执行 python manage.py migrate countries_app,它说 nothing to migrate,这是有道理的。

$ python3 manage.py migrate countries_app
Operations to perform:
  Apply all migrations: countries_app
Running migrations:
  Applying countries_app.0006_remove_country_population... OK

$ rm countries_app/migrations/0006_remove_country_population.py

$ python manage.py migrate countries_app

但是当我查看数据库table时,仍然没有字段population。我认为 Django 会重新创建它,因为我未应用迁移 0006 并且该字段再次在我的模型上定义。

我在 SO 上看到了一些答案,指示如下:取消应用所有迁移(python manage.py migrate countries_app zero),删除所有迁移文件,再次创建初始迁移然后迁移。

这对我来说太残酷了。我想指示 Django 重新创建不再存在的字段。有没有有效和更温和的方法来做到这一点?我对 Django Migrations 不是很了解,所以请多多包涵。谢谢。

您当然可以将该字段添加回模型并再次使用 makemigrations,然后向前迁移 (0006 -> 0007)。这会将列定义回数据库,但您必须用有效数据重新填充它。一个简单的迁移只会用默认值填充它。

经过一些调查和测试,从技术上讲,通过取消应用迁移 0006(回滚到 0005),Django 重新创建了曾经被删除的字段。我用另一个项目做了本地测试,是的,是的。

为什么回滚到迁移 0005 在我的案例中没有成功,这是未知的。我可能在我的 real 项目中搞砸了一些东西。因此,作为回答,我声明,通过回滚到以前的迁移,通常是您在这些情况下所需要的。

但是,如果事情真的一团糟并且 Django 没有重新创建曾经被删除但现在又回到您的模型中的字段,我看到 2 个备选方案:

  1. Nigel222 的回答。它会起作用,但仍然会带来额外的迁移,只是为了重新创建字段。

  2. 连接到数据库并手动创建字段。这将修复发生的异常,并且不会有额外的迁移来单独重新创建一个字段,该字段应该在迁移回滚时再次返回:

ALTER TABLE countries_app_country ADD population INTEGER;