英文:
How to set a new field in django models based on another field in another model?
问题
I have a model like this:
class Foo(models.Model):
...
status = models.PositiveSmallIntegerField(verbose_name=_('status'))
...
and another model like this:
class Bar(models.Model):
foo = models.ForeignKey(to=Foo, on_delete=models.CASCADE)
...
I want to remove the status
field from Foo
and add it to Bar
.
But this is a new field and must be filled with a value.
I want to fill it with the status value in bar_obj.foo
which is supposed to be deleted.
How can I do this?
英文:
I have a model like this:
class Foo(models.Model):
...
status = models.PositiveSmallIntegerField(verbose_name=_('status'))
...
and another model like this:
class Bar(models.Model):
foo = models.ForeignKey(to=Foo, on_delete=models.CASCADE)
...
I want to remove the status
field from Foo
and add it to Bar
.
But this is a new field and must be filled with a value.
I want to fill it with the status value in bar_obj.foo
which is supposed to be deleted.
How can I do this?
答案1
得分: 2
你可以分两步来完成这个操作:
步骤1:添加字段和数据迁移
首先,在Bar
模型中添加字段:
class Bar(models.Model):
foo = models.ForeignKey(to=Foo, on_delete=models.CASCADE)
status = models.PositiveSmallIntegerField(verbose_name=_('status'), default=0)
很重要的是给字段一个默认值,或者在这个阶段将其设为null=True
,这样我们可以临时给字段赋值。
然后运行makemigrations
命令,它会创建一个迁移。我们将修改这个迁移,添加一个数据迁移 [Django-doc]:
from django.db import migrations, models
from django.db.models import F
def copy_values(apps, schema_editor):
Bar = apps.get_model('<app_name>', 'Bar')
Bar.objects.update(status=F('foo__status'))
class Migration(migrations.Migration):
dependencies = [('app_name', '0123_prev_migration')]
operations = [
migrations.AddField(
'Bar', 'status', models.PositiveSmallIntegerField(default=0)
),
migrations.RunPython(copy_values),
]
建议您迁移此迁移并检查数据是否有效。
步骤2:从Foo
模型中移除status
字段
接下来,我们可以从Foo
模型中删除status
字段:
class Foo(models.Model):
...
# status = models.PositiveSmallIntegerField(verbose_name=_('status'))
如果需要的话,我们也可以从Bar
模型的status
字段中删除default
值。
然后再次创建一个迁移并执行迁移。
英文:
You can do this in two steps:
Step 1: add the field and a data migration
first add the field to the Bar
model:
<pre><code>class Bar(models.Model):
foo = models.ForeignKey(to=Foo, on_delete=models.CASCADE)
<b>status</b> = models.PositiveSmallIntegerField(verbose_name=_('status'), <b>default=0</b>)</code></pre>
It's important to give the field a default value, or make it null=True
in this stage, such that we can temporarily give the field values.
If we then run make migrations, it will make a migration. We will alter the migration, and add a data migration [Django-doc] to it:
<pre><code>from django.db import migrations, models
from django.db.models import F
def copy_values(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
Bar = apps.get_model('<em>app_name</em>', '<em>Bar</em>')
Bar.objects.update(<b>status=F('foo__status')</b>)
class Migration(migrations.Migration):
dependencies = [('<em>app_name</em>', '<em>0123_prev_migration</em>')]
operations = [
migrations.AddField(
&quot;<em>Bar</em>&quot;, &quot;status&quot;, models.PositiveSmallIntegerField(default=0)
),
migrations.RunPython(copy_values),
]</code></pre>
I would suggest that you migrate this migration and check if the data is valid.
Step 2: remove the status field on Foo
Next we can remove the status
field from the Foo
model:
<pre><code>class Foo(models.Model):
…
# <s>status = models.PositiveSmallIntegerField(verbose_name=_('status'))</s></code></pre>
we can also remove the <code>default=…</code> value from the status
field on Bar
if necessary.
We make another migration and we can migrate.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论