在AlterField django迁移上转换数据

Rod*_*ino 8 django django-models django-migrations

我有一个生产数据库,需要保持数据安全.我想更改模型中的字段并使用此更改转换该数据库中的所有数据.

老字段

class MyModel(models.Model):
    field_name = models.TimeField()
Run Code Online (Sandbox Code Playgroud)

改变了字段

class MyModel(models.Model):
    field_name = models.PositiveIntegerField()
Run Code Online (Sandbox Code Playgroud)

基本上我想在几分钟内转换TimeField值(有一个Time对象).

示例:我有一个对象time(hour=2, minute=0, second=0),我想将所有数据库表中的字段值转换为120应用迁移时的值.

小智 16

在过去,我总是在Djangos RunPython操作的帮助下完成这项工作.创建处理以下内容的自定义迁移.

  1. 更改字段名称.
  2. 添加所需类型的新字段.
  3. RunPython用于处理从一个转换为另一个的逻辑.
  4. 删除旧字段.


def migrate_time_to_positive_int(apps, schema_editor):

    MyModel = apps.get_model('myapp', 'MyModel')

    for mm in MyModel.objects.all():

        field_old_time = mm.field_name_old
        field_new_int = field_old_time.total_seconds() / 60
        mm.field_name = field_new_int 
        mm.save()

class Migration(migrations.Migration):

    operations = [
        migrations.RenameField(
            model_name='mymodel',
            old_name='field_name',
            new_name='field_name_old',
        ),
        migrations.AddField(
            model_name='mymodel',
            name='field_name',
            field=models.PositiveIntegerField(),
        ),
        migrations.RunPython(migrate_time_to_positive_int),
        migrations.RemoveField(
            model_name='mymodel',
            name='field_name_old',
        )
    ]
Run Code Online (Sandbox Code Playgroud)

field_name_old.total_seconds()/ 60可能需要调整,但你明白了.

  • 以“migrations.RunPython(migrate_time_to_positive_int,migrations.RunPython.noop)”的方式添加“migrations.RunPython.noop”,否则在降级的情况下,您将收到错误“django.db.migrations.exceptions.IrreversibleError” (2认同)

don*_*yor 7

我总是做的最安全的方法是:

  1. 创建另一个字段 field_name_new = models.PositiveIntegerField()
  2. 在生产数据库上迁移这个新字段
  3. 进行数据迁移(转换field_name值并将转换后的值移动到字段field_name_new
  4. 更改您的代码以便field_name_new使用
  5. 部署第 4 步
  6. 删除字段 field_name
  7. 在生产数据库上迁移第 6 步并部署它(第 6 步)

只有一个不好的一面:您可能会在步骤 4 和 5 中丢失一些数据。但您基本上可以将这些数据复制到新字段