Django 迁移,在删除旧字段之前根据旧字段计算新字段值?
Django migrations, calculate new fields value based on old fields before deleting old fields?
我们打算从旧的开始结束日期值修改我们的一个模型,以使用开始日期和长度。然而,这确实带来了挑战,因为我们想为我们的新字段提供默认值。
在这种情况下,是否可以 运行 迁移我们创建新字段的地方,根据模型旧的开始结束字段给它一个值
from datetime import date as Date
from django.db import models
class Period(models.Model):
#These are our new fields to replace old fields
period_length=models.IntegerField(default=12)
starting_date=models.DateField(default=Date.today)
#Old fields. We want to calculate the period length based on these before we remove them
start_day = models.IntegerField(default=1)
start_month = models.IntegerField(default=1)
end_day = models.IntegerField(default=31)
end_month = models.IntegerField(default=12)
开始月份和结束月份可以是 1 到 12 之间的任何时间,因此我们需要 运行 一堆计算来获得正确的长度。有没有办法让我们 运行 迁移中的一个函数,在添加新字段后,在调用删除旧字段之前计算它们的新值?
我知道我可以使用 makemigrations 创建基本的 add/remove 字段,但我想在两者之间添加值计算。我考虑过的其他选择是首先 运行 迁移以添加字段,然后使用自定义命令来计算字段,然后进行第二次迁移以删除旧字段,但这感觉它更有可能破坏某些东西。
我要做的是创建自定义迁移并在其中定义以下一系列操作:
- 添加长度字段。
- 使用计算更新长度字段。
- 删除旧字段。
因此您可以创建自定义迁移:
python manage.py makemigrations --name migration_name app_name --empty
然后在那里定义你需要的一系列操作:
operations = [
migrations.AddField (... your length field...),
migrations.RunPython (... the name of your function to compute and store length field ...),
migrations.RemoveField (... your end_date field ...),
]
编辑:
您的迁移应该如下所示(update_length_field 将是您的函数,具有相同的参数):
class Migration(migrations.Migration):
dependencies = [
('app_name', 'your_previous_migration'),
]
def update_length_field(apps, schema_editor):
for period in Period.objects.all():
period.length = ... whatever calculations you need ...
period.save()
operations = [
migrations.AddField (... your length field...),
migrations.RunPython(update_length_field),
migrations.RemoveField (... your end_date field ...),
]
在基本层面上,它应该是这样的。
现在,如果您希望能够回滚迁移,则必须定义第二个函数,其作用与 update_length_field 完全相反做。并把它作为migrations.RunPython.
的第二个参数
此外,如果您希望迁移与模型的未来更改兼容(如果只部署一次迁移则不需要),您必须从代码的历史版本中获取模型,类似于:
def update_length_field(apps, schema_editor):
Period = apps.get_model("app_name", "Period")
for period in Period.objects.all():
period.length = ...
period.save()
更多信息在这里:
https://docs.djangoproject.com/en/4.0/ref/migration-operations/
我们打算从旧的开始结束日期值修改我们的一个模型,以使用开始日期和长度。然而,这确实带来了挑战,因为我们想为我们的新字段提供默认值。
在这种情况下,是否可以 运行 迁移我们创建新字段的地方,根据模型旧的开始结束字段给它一个值
from datetime import date as Date
from django.db import models
class Period(models.Model):
#These are our new fields to replace old fields
period_length=models.IntegerField(default=12)
starting_date=models.DateField(default=Date.today)
#Old fields. We want to calculate the period length based on these before we remove them
start_day = models.IntegerField(default=1)
start_month = models.IntegerField(default=1)
end_day = models.IntegerField(default=31)
end_month = models.IntegerField(default=12)
开始月份和结束月份可以是 1 到 12 之间的任何时间,因此我们需要 运行 一堆计算来获得正确的长度。有没有办法让我们 运行 迁移中的一个函数,在添加新字段后,在调用删除旧字段之前计算它们的新值?
我知道我可以使用 makemigrations 创建基本的 add/remove 字段,但我想在两者之间添加值计算。我考虑过的其他选择是首先 运行 迁移以添加字段,然后使用自定义命令来计算字段,然后进行第二次迁移以删除旧字段,但这感觉它更有可能破坏某些东西。
我要做的是创建自定义迁移并在其中定义以下一系列操作:
- 添加长度字段。
- 使用计算更新长度字段。
- 删除旧字段。
因此您可以创建自定义迁移:
python manage.py makemigrations --name migration_name app_name --empty
然后在那里定义你需要的一系列操作:
operations = [
migrations.AddField (... your length field...),
migrations.RunPython (... the name of your function to compute and store length field ...),
migrations.RemoveField (... your end_date field ...),
]
编辑:
您的迁移应该如下所示(update_length_field 将是您的函数,具有相同的参数):
class Migration(migrations.Migration):
dependencies = [
('app_name', 'your_previous_migration'),
]
def update_length_field(apps, schema_editor):
for period in Period.objects.all():
period.length = ... whatever calculations you need ...
period.save()
operations = [
migrations.AddField (... your length field...),
migrations.RunPython(update_length_field),
migrations.RemoveField (... your end_date field ...),
]
在基本层面上,它应该是这样的。
现在,如果您希望能够回滚迁移,则必须定义第二个函数,其作用与 update_length_field 完全相反做。并把它作为migrations.RunPython.
的第二个参数此外,如果您希望迁移与模型的未来更改兼容(如果只部署一次迁移则不需要),您必须从代码的历史版本中获取模型,类似于:
def update_length_field(apps, schema_editor):
Period = apps.get_model("app_name", "Period")
for period in Period.objects.all():
period.length = ...
period.save()
更多信息在这里: https://docs.djangoproject.com/en/4.0/ref/migration-operations/