Django Migrations添加默认为模型函数的字段

时间:2015-04-22 04:36:57

标签: django django-models django-migrations

我在Django模型中添加了一个新的,不可为空的字段,并尝试使用迁移来部署该更改。如何将现有模型的默认值设置为这些模型的某些函数而不是常量?

举个例子,假设我之前有一个created_on字段,我刚刚添加了一个updated_on字段,其值最初要设置为模型的created_on。我将如何在迁移中执行此操作?

这是我想要开始的:

    migrations.AddField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(default=????, auto_now=True),
        preserve_default=False,
    ),

3 个答案:

答案 0 :(得分:67)

我刚刚学会了如何通过一次迁移来实现这一目标!

运行makemigrations时,django会要求您设置一次性默认值。定义您可以在这里保留的任何内容,并最终得到您提到的迁移AddField

migrations.AddField(
    model_name='series',
    name='updated_as',
    field=models.DateTimeField(default=????, auto_now=True),
),

将此操作更改为3个操作:

  1. 最初将字段设为可为空,因此将添加该列。
  2. 根据需要调用函数来填充字段。
  3. 更改字段(使用AlterField)使其不可为空(如上所述,没有默认值)。
  4. 所以你最终得到类似的东西。

    migrations.AddField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(null=True, auto_now=True),
    ),
    migrations.RunPython(set_my_defaults, reverse_func),
    migrations.AlterField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(auto_now=True),
    ),
    

    将您的功能定义为:

    def set_my_defaults(apps, schema_editor):
        Series = apps.get_model('myapp', 'Series')
        for series in Series.objects.all().iterator():
            series.updated_as = datetime.now() + timedelta(days=series.some_other_field)
            series.save()
    
    def reverse_func(apps, schema_editor):
        pass  # code for reverting migration, if any
    

    除此之外,你知道,并不可怕;考虑使用F expressions和/或database functions来提高大型数据库的迁移性能。

答案 1 :(得分:18)

您需要在两次迁移中执行此操作。首先,添加你的字段,但可以为空。像往常一样创建迁移文件。之后,将你的领域设置为不可空,并再次运行makemigrations,但还没有迁移。打开第二个迁移并在顶部定义一个函数:

def set_field_values(apps, schema_editor):
    # use apps.get_model("app_name", "model_name") and set the defualt values

然后,在您的迁移文件中有一个操作列表。 之前更改字段操作添加

RunPython(set_field_values)

它应该这样做

答案 2 :(得分:4)

您还应该为函数set_my_defaults()定义一个反向,以防将来还原迁移的内容。

def reverse_set_default(apps, schema_editor):
    pass

在这种情况下,反向功能无需执行任何操作,因为您要删除该字段。

并将其添加到RunPython:

migrations.RunPython(set_my_defaults, reverse_set_default),