Django:在数据不丢失的情况下将CharField转换为TextField

14 投票
3 回答
7594 浏览
提问于 2025-04-16 16:51

有没有办法把一个字符字段(CharField)改成文本字段(TextField),而且还能保持这个列里的数据不变呢?

现在我有以下的内容:

class TestLog(models.Model):
    failed_reqs = models.CharField(max_length=DB_MAX_CHAR_LENGTH, blank=True)
    passed_reqs = models.CharField(max_length=DB_MAX_CHAR_LENGTH, blank=True)

但是目前这个字符字段的最大长度是500,结果发现有时候这个字段的数据会超过这个长度,所以我想改成:

class TestLog(models.Model):
    failed_reqs = models.TextField(blank=True)
    passed_reqs = models.TextField(blank=True)

我该怎么做才能在生产数据库中保持我的数据不变呢?

Djangobook 里详细说明了如何添加和删除字段,我也试着用 South 来做到这一点,但 South 给我报了错,查看报错前的输出,似乎 South 是在删除然后重新创建数据库。这就是 South 的 数据迁移 吗?

3 个回答

5

首先,我会继续考虑使用South这个工具。以下是我会尝试的步骤:

1) 使用South进行模式迁移,创建两个新的文本字段,名字可以叫“failed_reqs_txt”和“passed_reqs_txt”。

2) 创建一个数据迁移,把旧字段的数据迁移到新字段。

3) 创建一个模式迁移,删除原来的“failed_reqs”和“passed_reqs”字段。

---- 如果你需要字段的名字和原来的保持一致,我会接着进行:

4) 创建一个模式迁移,添加“failed_reqs”和“passed_reqs”作为文本字段。

5) 创建一个数据迁移,把“failed_reqs_txt”和“passed_reqs_txt”的数据迁移到“failed_reqs”和“passed_reqs”字段。

6) 创建一个模式迁移,删除“failed_reqs_txt”和“passed_reqs_txt”字段。

虽然这需要很多次迁移,但这样可以把每个变化拆分成小的迁移步骤。我会先尝试这个方法。我不太明白为什么South会删除并重新创建数据库。你在给项目添加South时,有运行“convert_to_south”这个选项吗?我觉得这个选项可以模拟一次迁移,让South知道它是在处理一个已有的项目,而不是一个新项目。

另外,你也可以直接对数据库进行一些ALTER操作,来改变字段类型,然后把model.py中的CharField更新为TextField。Postgres据说支持这样隐式地改变数据类型。(见第5.5.6节。)我不太确定mysql,但我觉得应该也是一样的。(从CharField到TextField应该是兼容的转换)

无论如何,在进行任何这样的更改之前,我会备份我的数据。希望这些信息对你有帮助。

25

这个问题可以通过Django的迁移功能来解决(1.7及以上版本)。如果你把字段类型从字符字段(CharField)改成文本字段(TextField),生成的迁移文件会是AlterField,这样就能正确处理这个变化。

5

假设你可以访问数据库,正如你提到的Django在添加和删除列时的方式,我列出了Postgresql和MySQL的操作方法,因为你没有说明你使用的是哪种数据库。

Postgresql:
BEGIN;
    ALTER TABLE "TestLog"
        ALTER COLUMN "failed_reqs" TYPE TEXT,
        ALTER COLUMN "passed_reqs" TYPE TEXT;
COMMIT;

MySQL:
BEGIN;
    ALTER TABLE TestLog
        MODIFY failed_reqs TEXT NULL,
        MODIFY passed_reqs TEXT NULL;
COMMIT;

我强烈建议在进行这些更改之前备份你的数据库。

撰写回答