Django Migrations Добавление поля по умолчанию в качестве функции модели

Я добавил новое поле, не допускающее nullable, в мою модель Django и пытаюсь использовать миграции для развертывания этого изменения. Как установить значение по умолчанию для использования в существующих моделях как функцию этих моделей, а не константу?

В качестве примера скажем, что у меня ранее было поле created_on, и я просто добавил поле updated_on, значение которого я хочу сначала установить в модель created_on. Как мне это сделать при миграции?

Это то, что я пытаюсь начать с:

    migrations.AddField(
        model_name='series',
        name='updated_as',
        field=models.DateTimeField(default=????, auto_now=True),
        preserve_default=False,
    ),

Ответы

Ответ 1

Я только что научился делать это с помощью одного переноса!

при запуске makemigrations django должен попросить вас установить одноразовое значение по умолчанию. Определите, что вы можете здесь сделать, чтобы он был счастлив, и вы в конечном итоге с помощью миграции AddField, которую вы упомянули.

migrations.AddField(
    model_name='series',
    name='updated_as',
    field=models.DateTimeField(default=????, auto_now=True),
),

Измените эту операцию на 3 операции:

  • изначально сделать поле нулевым, поэтому будет добавлен столбец.
  • вызовите функцию для заполнения поля по мере необходимости.
  • измените поле (с помощью AlterField), чтобы сделать его недействительным (например, выше, без значения по умолчанию).

чтобы вы получили что-то вроде.

migrations.AddField(
    model_name='series',
    name='updated_as',
    field=models.DateTimeField(null=True, auto_now=True),
),
migrations.RunPython(set_my_defaults),
migrations.AlterField(
    model_name='series',
    name='updated_as',
    field=models.DateTimeField(auto_now=True),
),

с вашей функцией, определенной как что-то вроде:

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()

кроме, вы знаете, не страшно.

Ответ 2

Вам нужно сделать это за две миграции. Прежде всего, добавьте свое поле, но сделайте nullable. Создайте файл миграции, как обычно. После этого установите для поля значение null-nullable и снова запустите makemigrations, но пока не запустите его. Откройте вторую миграцию и определите функцию вверху:

def set_field_values(apps, schema_editor):
    # use apps.get_model("app_name", "model_name") and set the defualt values

то в вашем файле миграции есть список операций. До операция изменения поля добавляет

RunPython(set_field_values)

и он должен это сделать