Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django migrations/South: New column take default value another value from the same record

I want to add a new column to an already existing table, but I want to give it a default value dependent on already existing data:

e.g. Each record has a start_date. Now I want to add an open_until column, and I want to fill it with the value for start_date of each existing record. (the upcoming records will be able to pick different value)

Is there a friendly way to do this?

like image 399
confused00 Avatar asked Sep 01 '14 15:09

confused00


2 Answers

You can also do it within South. The only caveat is that you need two steps for that:

  1. A schema migration that adds the open_until column

    from django.db import models
    import datetime
    
    class MyModel(models.Model):
        start_date = models.DateField(),
        open_until = models.DateField(default=datetime.date.today),
    

    $ python manage.py schemamigration --auto appname

  2. A data migration that fills existing rows with the value of that other column

    $ python manage.py datamigration appname populate_open_until

    import datetime
    
    class Migration(DataMigration):
    
        def forwards(self, orm):
            "Set open_until value to that of start_date for existing rows"
            for t in orm.MyModel.objects.all():
                t.open_until = t.start_date
                t.save()
    
        def backwards(self, orm):
            "Revert back to default"
            for t in orm.MyModel.objects.all():
                t.open_until = datetime.date.today
                t.save()
    

(optional) In step 1 you can either provide a temporary default value or make it optional and add a 3rd step

  1. A schema migration that makes the open_until column mandatory.
like image 68
jgiralt Avatar answered Oct 11 '22 09:10

jgiralt


In Python 3.8 I first add fields to MyApp models file and it looks like:

from django.db import models
import datetime

class MyModel(models.Model):
    start_date = models.DateField(),
    open_until = models.DateField(default=datetime.date.today),

Then, after running manage.py makemigrations add this lines to new migrations file is created:

def forward(apps, schema_editor):
    my_model_objects = apps.get_model('MyApp', 'MyModel').objects.all()
    for t in my_model_objects:
        t.open_until = t.start_date
        t.save()

def reverse(apps, schema_editor):
    pass

class Migration(migrations.Migration):
    operations = [
        " the base operations is here " ,
        migrations.RunPython(forward, reverse),
    ]
like image 27
motad333 Avatar answered Oct 11 '22 08:10

motad333