3

I have a model:

class Model(models.Model):
    price = models.DecimalField(...)

There are already Model objects in production database. Now I add price_total field to this model which can't be null.

class Model(models.Model):
    price = models.DecimalField(...)
    price_total = models.DecimalField(...)

I want this price_total to be equal to price right after migration.

Something like:

price_total = models.DecimalField(default=this_object.price,...)

Is it possible to do it somehow?

The only thing I know about is:

  1. make price_total nullable
  2. makemigrations + migrate
  3. set price_total equal to price for example through django shell
  4. make price_total not nullable
  5. makemigration + migrate

But this way has multiple disadvantages, you can forgot to do that in production, it has many steps etc...

Is there a better way?

Milano
  • 18,048
  • 37
  • 153
  • 353

2 Answers2

9

you can do it by manual edit migration,

  1. do makemigrations with null
  2. do makemigrations with not null
  3. Edit first make migration by add datamigration with update and move operations from second migrate file
  4. remove the second migrations file,

for example:

from django.db import migrations, models
from django.db.models import F

def set_price_total(apps, schema_editor):
    # Change the myapp on your
    Model = apps.get_model('myapp', 'Model')
    Model.objects.update(price_total=F('price'))


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='model',
            name='price_total',
            field=models.DecimalField(
                decimal_places=2, max_digits=10, null=True),
        ),

        migrations.RunPython(set_price_total),

        migrations.AlterField(
            model_name='model',
            name='price_total',
            field=models.DecimalField(
                decimal_places=2, default=1, max_digits=10),
            preserve_default=False,
        ),
    ]
Brown Bear
  • 19,655
  • 10
  • 58
  • 76
3

You are on track to do it properly.

Just make sure step 3 in done in a datamigration (certainly not through django shell).

This way you won't forget to run it on production.

I'm pretty sure you can't do both add the column and setting the value to be the same as another column.

To convince yourself, you can search for vanilla SQL implementation like https://stackoverflow.com/a/13250005/1435156

Benjamin Toueg
  • 10,511
  • 7
  • 48
  • 79