且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Django 迁移添加具有默认值的字段作为模型的函数

更新时间:2023-01-30 10:50:24

我刚刚学会了如何通过一次迁移来做到这一点!

在运行 makemigrations 时,django 应该要求您设置一次性默认值.在这里定义你能做的一切,让它开心,你最终会得到你提到的迁移 AddField.

migrations.AddField(模型名称='系列',name='updated_as',field=models.DateTimeField(default=????, auto_now=True),保留默认值=假,),

把这一个操作改成3个操作:

  1. 最初使字段可以为空,以便添加该列.
  2. 调用函数以根据需要填充该字段.
  3. 更改字段(使用 AlterField)使其不可为空(如上述,没有默认值).

所以你最终会得到这样的结果:

migrations.AddField(模型名称='系列',name='updated_as',field=models.DateTimeField(null=True, auto_now=True),),migrations.RunPython(set_my_defaults, reverse_func),迁移.AlterField(模型名称='系列',name='updated_as',field=models.DateTimeField(auto_now=True),),

你的函数定义如下:

def set_my_defaults(apps, schema_editor):系列 = apps.get_model('myapp', 'Series')对于 Series.objects.all().iterator() 中的系列:series.updated_as = datetime.now() + timedelta(days=series.some_other_field)系列.save()def reverse_func(apps, schema_editor):pass # 用于恢复迁移的代码,如果有的话

除了,你知道,并不可怕.

注意:考虑使用 F 表达式和/或 数据库函数,用于提高大型数据库的迁移性能.>

I added a new, non-nullable field to my Django model and am trying to use migrations to deploy that change. How would I set default value to use for existing models to be some function of those models rather than a constant?

As an example let's say I previously had a created_on field and I just added an updated_on field whose value I want to set initially to the model's created_on. How would I do this in a migration?

This is what I am trying to start with:

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

I just learnt how to do this with a single migration!

When running makemigrations django should ask you to set a one-off default. Define whatever you can here to keep it happy, and you'll end up with the migration AddField you mentioned.

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

Change this one operation into 3 operations:

  1. Initially make the field nullable, so the column will be added.
  2. Call a function to populate the field as needed.
  3. Alter the field (with AlterField) to make it not nullable (like the above, with no default).

So you end up with something like:

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),
),

with your functions defined as something like:

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

Except, you know, not terrible.

Note: Consider using F expressions and/or database functions to increase migration performance for large databases.