gpt4 book ai didi

django - 在django中将多对多关系转换为一对多

转载 作者:行者123 更新时间:2023-12-04 15:36:25 25 4
gpt4 key购买 nike

我要实现的目标

到目前为止,我们的模型具有如下所示的多对多关系。

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 的记录将始终有一个对 A 对象的引用。

此外,由于这些表已在生产中使用,因此我们也需要迁移现有数据。

到目前为止我尝试过的事情

从模型 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>

基本上,在完成上述步骤后,它会将具有 a_id 的记录更新为 b 的某个对象的 id。

我面临的问题

当我尝试运行 makemigrations 时,它要求提供数据的默认值,但我不确定该放什么。在模型 A 中,我可以将数据字段指向 B 的任何记录,但是我将失去对第三个表 C 的使用,而且表 C 在整个系统中被广泛使用。那么,我需要删除表 C 吗?另外,想知道有没有更好的方法来改变多对多到一对多的关系。任何帮助都会很有用。

最佳答案

在这种情况下,当您的数据位于中间表中时,我建议您执行以下操作。

  1. 将临时列添加到您的 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)

然后执行python manage.py makemigrations

  1. 创建一个空的迁移文件并让它运行这段代码,将表 C 中的所有 A-B 关系数据复制到表 A
# 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)
]
  1. 从您的 A 模型和 makemigtations
  2. 中删除 data
  3. 在您的A 模型上将tmp_data 列重命名为data,然后makemigrations

    Careful, make sure that makemigrations won't remove the tmp_data and data and then adds new field data, this is going to cause loss of data, I will show you how to do it in the snippet below.

内部迁移文件,如果发生这种情况

...
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'
),
]
...
  1. python manage.py 迁移

这应该永远有效。之后,如果你想删除表 C,这取决于你,因为它里面的数据已经安全地迁移到表 A

关于django - 在django中将多对多关系转换为一对多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59609667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com