Новое поле Django: как установить вызываемый по умолчанию объект для существующих объектов

У меня есть модель:

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

В рабочей базе данных уже есть Model объектов. Теперь я добавляю в эту модель поле price_total, которое не может быть null.

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

Я хочу, чтобы это price_total было равно price сразу после миграции.

Что-то типа:

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

Можно ли это как-то сделать?

Единственное, о чем я знаю, это:

  1. сделать price_total обнуляемым
  2. makemigrations + миграция
  3. установить price_total равным price например через django shell
  4. сделать price_total не обнуляемым
  5. сделать миграцию + мигрировать

Но у этого способа есть несколько недостатков, вы можете забыть сделать это в продакшене, у него много шагов и т.д...

Есть ли способ лучше?


person Milano    schedule 19.06.2018    source источник


Ответы (2)


вы можете сделать это путем ручной миграции редактирования,

  1. сделать makemigrations с нулем
  2. делать makemigrations с ненулевым значением
  3. Отредактируйте первую миграцию, добавив миграцию данных с обновлением и перемещением операций из второго файла миграции.
  4. удалить второй файл миграции,

Например:

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,
        ),
    ]
person Brown Bear    schedule 19.06.2018

Вы на пути к тому, чтобы сделать это правильно.

Просто убедитесь, что шаг 3 выполнен в datamigration (конечно, не через оболочку django).

Таким образом, вы не забудете запустить его на производстве.

Я почти уверен, что вы не можете одновременно добавить столбец и установить значение, совпадающее с другим столбцом.

Чтобы убедиться в этом, вы можете поискать ванильную реализацию SQL, например https://stackoverflow.com/a/13250005/1435156.

person Benjamin Toueg    schedule 19.06.2018
comment
Я думаю, что основная проблема связана с частью this_object. - person Willem Van Onsem; 19.06.2018