4

假设我创建了两个模型:

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)

我怎样才能做到这一点而不会丢失我的条目?我试图查看 South 文档,但没有找到这种转换方式...

4

2 回答 2

7

这很重要,我认为您将需要三个迁移:

  1. 添加ForeignKey.
  2. 转换ManyToManyForeignKey(使用forwards方法)。
  3. 删除ManyToMany.

您可以将 1 和 2 或 2 和 3 合并在一起,但我不建议这样做。
此外,您还应该backwards为 2 实现一个方法。

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 中更新使用这些关系的代码。

于 2012-12-19T13:56:30.580 回答
6

基于 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 应用程序。显示了正向和反向迁移代码(正如 Thomas 所提到的,如果事先存在多个关系,则运行此迁移可能会导致数据丢失,因此请注意)。

于 2016-02-19T16:23:05.307 回答