Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
642 views
in Technique[技术] by (71.8m points)

Django Migrations Add Field with Default as Function of Model

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,
    ),
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

  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; consider using F expressions and/or database functions to increase migration performance for large databases.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...