confused00
confused00

Reputation: 2612

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?

Upvotes: 8

Views: 6734

Answers (3)

hn_tired
hn_tired

Reputation: 942

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

Upvotes: 2

elmonkeylp
elmonkeylp

Reputation: 2764

As I replied to you, setting a dynamic default value in a database level is not necessary if you are working with a framework :)

The best way, I think, is setting the value of your column in the view before saving the record.

models.py

from django.db import models

class MyModel(models.Model):
    start_date = models.DateField(),
    open_until = models.DateField(),

forms.py from django.forms import ModelForm

class MyForm(forms.ModelForm):
    model = MyModel

    fields = ('start_date')

class view

from django.http import HttpResponse
from django.views.generic import CreateView
from .models import MyModel


MyView(CreateView):
    form_class = MyForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            submitted_form = form.save(commit=False)
            submitted_form.open_until = form.cleaned_data["start_date"]
            submitted_form.save()
            # return an HttpResponse here

For the previous entries, make a view to call just one time, and then loop through all the records and save the values of the new column according the value of the order column.

Something like this:

from django.http import HttpResponse

def set_open_until_values(request)
    records = MyModel.objects.all()
    for record in records:
        record.open_until = record.start_date
        record.save()
    return HttpResponse("Done!!")

Upvotes: -3

jgiralt
jgiralt

Reputation: 690

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.

Upvotes: 14

Related Questions