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),
),
Change this one operation into 3 operations:
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; consider using F expressions and/or database functions to increase migration performance for large databases.