Django South:在数据迁移中更改字段类型

19

我要将一个字段从CharField改为IntegerField,字段名称保持不变。新创建的字段将基于旧字段。例如,如果旧字段是“L”,那么它将有数字“1”。我该如何在forwards()函数中完成这个操作?

2个回答

19
  • 更正的方法是将其分为三个迁移:
    1. 首先进行模式迁移,添加新的IntegerField字段。
    2. 然后进行数据迁移,将来自CharField的数据转换为IntegerField
    3. 最后进行模式迁移,以删除现在未使用的CharField

    如果您希望您新添加的IntegerField与即将删除的CharField具有相同的名称,则可能需要第四个迁移。

    假设在您的模型文件中尚未添加IntegerField,则应按以下步骤进行操作:

    1. 向您的模型中添加IntegerField
    2. 为包含您的模型的应用程序创建模式迁移。 如果它不为null,您可能需要在此处为新添加的字段指定默认值。
    3. 为包含您的模型的应用程序创建数据迁移(使用datamigration)。 在新创建的DataMigration类的forwards()方法中编写转换数据的逻辑。请尽可能使用update管理器方法,而不是迭代所有数据库行。如果您使用字典(例如{'L': 1, ...} )声明您的转换逻辑,则在此时实现backwards()也相当容易,因为该操作是可逆的。在forwards()中确保您没有忽略任何特殊情况,这对我过去帮助很大。
    4. 从您的模型中删除CharField
    5. 为包含您的模型的应用程序创建模式迁移,以便DROP现在未使用的列。

    将此操作分为三个迁移而不是在空白模板中编写整个逻辑有几个优点:

    1. 自动生成DDL操作: ADD/DROP逻辑已由South自动生成,您无需担心在数据库列中引入错别字。
    2. 完全可逆的操作: 如果您花时间实现了DataMigration.backwards()用于转换步骤,那么您应该能够完全撤销整个操作。如果需要回滚到代码先前版本进行测试,或者在更新生产代码库时作为安全措施,这非常方便。
    3. 操作的原子性: 每个操作被隔离并在其自己的事务中执行,不会让您的数据库和South迁移处于不一致状态。例如,如果所有操作在单个迁移中执行(在这种情况下是相同的forwards()方法),并且在数据迁移步骤期间发生异常(例如由于转换dict中的未处理值而导致的KeyError)。如果您正在使用不支持事务模式的ORDBMS架构更改,则不能立即在修复数据迁移部分后重新运行您的迁移,您必须手动删除新添加的IntegerField列。在迁移生产数据库时,您不希望遇到这样的问题。
    4. 执行干扰试验的能力:这对于迁移生产数据库也非常方便。

    2
    这就是我最终所做的。这与 South migrate DateField to IntegerField 相似。 - user2233706
    太好了!我赶紧写下来,希望你还没有在单个迁移中压缩所有内容。希望我的答案能为你提供额外的洞察力,解释为什么你应该这样做。 - Simon Charette

    1

    对于相同的情况,我只需要跟随3个步骤。

    1)将文件类型从CharField更改为IntegerField,

    2)ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (col_name::integer); 或者

    ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (trim(col_name)::integer); # 如果您的Char或Text字段中有空格,并且如果您的表中有数据,这些数据应该是整数字符串。

    3)现在应用迁移。


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