在django中将多对多关系转换为一对多关系
我正在努力实现的目标 到目前为止,我们已经有了如下所示的多对多关系的模型在django中将多对多关系转换为一对多关系,django,python-3.x,Django,Python 3.x,我正在努力实现的目标 到目前为止,我们已经有了如下所示的多对多关系的模型 class A(models.Model): name = models.CharField(max_length=255) data = models.ManyToManyField(B, related_name='data', through='C') class B(models.Model): name=models.CharField(max_length=255) class C(
class A(models.Model):
name = models.CharField(max_length=255)
data = models.ManyToManyField(B, related_name='data', through='C')
class B(models.Model):
name=models.CharField(max_length=255)
class C(models.Model):
a = ForeignKey(A)
b = ForeignKey(B)
c = model.CharField(max_length=255)
active = models.BooleanField(default=True)
and so on....
尽管Django会自动为多对多关系创建一个中间表,但如果我们不显式定义它,您可以注意到,我已经显式定义了第三个中间表来存储关于每个关系的额外元数据
因此,根据新的业务需求,我们需要从表中删除多对多关系,并将其替换为一对多关系,即B的每个记录可以有多个对obj A的引用,但A的记录将始终有一个对obj的引用
此外,由于这些表已经在生产中使用,因此我们也需要迁移现有数据
到目前为止我已经尝试过的事情
从模型A中删除多对多
class A(models.Model):
name = models.CharField(max_length=255)
data = models.ForeignKey(B)
已更新模型C的现有行
例如:
#this might return more than one obj because of many to many relationship
test = C.objects.filter(a__id=<a obj id>)
for t in test:
t.b_id = <some id pointing to record of B>
#由于多对多关系,这可能会返回多个obj
test=C.objects.filter(a\u id=)
对于测试中的t:
t、 b_id=
基本上,在完成上述步骤后,它将用a_id更新记录,以将b的某个obj的id更新
我面临的问题
当我试图运行makemigrations
时,它询问数据的默认值,我不确定该放什么。在模型A中,我可以将数据字段指向B的任何记录,但是我将失去第三个表C的使用,而且表C在整个系统中被广泛使用。
那么,我需要放弃表C吗?
另外,我想知道有没有更好的方法来改变多对多对一对多的关系。
任何帮助都会很有用。在这种情况下,当您的数据位于中间表中时, 我建议你做以下几点
A
表中添加和临时列python manage.py makemigrations
A-B
关系数据从表C
复制到表A
python manage.py迁移
C
,则由您决定,因为其中的数据会安全地迁移到表A
class A(models.Model):
name = models.CharField(max_length=255)
data = models.ManyToManyField(B, related_name='data', through='C')
# the on_delete part is not related, I added it just to avoid errors.
tmp_data = models.ForeignKey(B, on_delete=models.DO_NOTHING)
# Command
python manage.py makemigrations <<<APP_NAME>>> --empty
# Inside Empty migrations file
def migrate_c_to_a(apps, schema_editor):
C = apps.get_model('<<<APP NAME>>>', 'C')
for c in C.objects.all().iterator():
a = c.a
a.tmp_data = c.b
a.save()
class Migration(migrations.Migration):
...
...
operations = [
migrations.RunPython(migrate_c_to_a)
]
...
operations = [
migrations.RemoveField(
model_name='a',
name='tmp_data',
),
migrations.RemoveField(
model_name='a',
name='data',
),
migrations.AddField(
model_name='a',
name='data',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='tsting.B'),
),
]
...
...
operations = [
migrations.RemoveField(
model_name='a',
name='data',
),
migrations.RenameField(
model_name='a',
old_name='tmp_data',
new_name='data'
),
]
...