Django:将ManyToManyField转换为ForeignKey

时间:2012-12-19 13:49:45

标签: python django django-models

假设我创建了两个模型:

class Car(models.Model):
    name =  models.CharField(max_length=50)
    size =  models.IntegerField()


class Manufacturer(models.Model):
    name =  models.CharField(max_length=50)
    country =  models.CharField(max_length=50)
    car = models.ManyToManyField(Car)

我在两个模型中添加了条目,然后我意识到每辆车只与一个独特的制造商有关。所以,我应该将ManyToManyField转换为ForeignKey:

class Car(models.Model):
    name =  models.CharField(max_length=50)
    size =  models.IntegerField()
    manufacturer = models.ForeignKey(Manufacturer)

class Manufacturer(models.Model):
    name =  models.CharField(max_length=50)
    country =  models.CharField(max_length=50)

如何在不丢失参赛作品的情况下做到这一点?我试着查看南方文档,但我没有找到这种转换方式......

2 个答案:

答案 0 :(得分:7)

这非常重要,我认为您需要进行三次迁移:

  1. 添加ForeignKey
  2. ManyToMany转换为ForeignKey(使用forwards方法)。
  3. 删除ManyToMany
  4. 你可以将1和2或2和3合并在一起,但我不推荐它 此外,您还应该为2实现backwards方法。

    2. forwards示例将是:

    class Migration(SchemaMigration):
        def forwards(self, orm):
            for manufacturer in orm.Manufacturer.objects.all():
                 for car in manufacturer.car.all():
                      car.manufacturer = manufacturer
                      car.save()
    

    请注意:

    • 此处尚无backwards方法。
    • 需要对此进行广泛测试:迁移是您应该格外小心的事情。
    • 如果汽车有两个制造商,最后一个将被保留。
    • 效率非常低,我们按照制造商的每辆车进行查询!

    您还需要在步骤2. / 3中更新使用这些关系的代码。

答案 1 :(得分:5)

根据Thomas Orozco提供的优秀答案,我想为Django> = 1.7提供解决方案(基本上,第2点将ManyToMany转换为ForeignKey 是新的变化Django的版本)。所以这里是第二次迁移的代码:

class Migration(migrations.Migration):

    def migrate_m2m_to_fk(apps, schema_editor):
        Manufacturer = apps.get_model("app", "Manufacturer")
        for manufacturer in Manufacturer.objects.all():
             for car in manufacturer.car.all():
                  car.manufacturer = manufacturer
                  car.save()

    def migrate_fk_to_m2m(apps, schema_editor):
        Car = apps.get_model("app", "Car")
        for c in Car.objects.all():
            if c.manufacturer:
                c.manufacturer.car.add(c)
                c.manufacturer.save()

    operations = [
        migrations.RunPython(migrate_m2m_to_fk, migrate_fk_to_m2m)
    ]

其中" app"是模型所在的Django应用程序。显示了正向和反向迁移代码(正如托马斯所提到的,如果预先存在多个关系,运行此迁移可能会导致数据丢失,所以请注意)。